一、Makefile函数用法
A = a b c
#对于$(A)中的每一个变量 f,变成$(f).o 这样的话A = a.o b.o c.0了。
B = $(foreach f, $(A), $(f).o)
C = a b c d/
#从变量C中取出符合/这种格式的值,%是通配符,下面相反
D = $(filter %/, $(C))
E = $(filter-out %/, $(C))
# *.c 定义了一种文件格式,就是.c文件,wildcard取出其中存在的文件
files = $(wildcard *.c)
#能判断出来哪些文件真实存在
files2 = a.c b.c c.c d.c e.c abc
files3 = $(wildcard $(files2))
#替换操作,把files2文件中的所有.c替换为.h
dep_files = $(patsubst %.c,%.d,$(files2))
all:
@echo B = $(B)
@echo D = $(D)
@echo E = $(E)
@echo files = $(files)
@echo files3 = $(files3)
@echo dep_files = $(dep_files)
Makefile实例
a. 改进: 支持头文件依赖
http://blog.csdn.net/qq1452008/article/details/50855810
gcc -M c.c // 打印出依赖
gcc -M -MF c.d c.c // 把依赖写入文件c.d
gcc -c -o c.o c.c -MD -MF c.d // 编译c.o, 把依赖写入文件c.d
objs = a.o b.o c.o
#全部文件替换为 .文件.d类型 a.o->.a.o.d
dep_files := $(patsubst %,.%.d, $(objs))
#判断出真实存在的文件
dep_files := $(wildcard $(dep_files))
# -I 选项,作为编译选项,包含的目录
CFLAGS = -Werror -Iinclude
test: $(objs)
gcc -o test $^
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean
wildcard描述
二、时钟体系图
.text
.global _start
_start:
/* 关闭看门狗 */
ldr r0, =0x53000000
ldr r1, =0
str r1, [r0]
/* 设置MPLL, FCLK : HCLK : PCLK = 400m : 100m : 50m */
/* LOCKTIME(0x4C000000) = 0xFFFFFFFF */
ldr r0, =0x4C000000
ldr r1, =0xFFFFFFFF
str r1, [r0]
/* CLKDIVN(0x4C000014) = 0X5, tFCLK:tHCLK:tPCLK = 1:4:8 */
ldr r0, =0x4C000014
ldr r1, =0x5
str r1, [r0]
/* 设置CPU工作于异步模式 */
mrc p15,0,r0,c1,c0,0
orr r0,r0,#0xc0000000 //R1_nF:OR:R1_iA
mcr p15,0,r0,c1,c0,0
/* 设置MPLLCON(0x4C000004) = (92<<12)|(1<<4)|(1<<0)
* m = MDIV+8 = 92+8=100
* p = PDIV+2 = 1+2 = 3
* s = SDIV = 1
* FCLK = 2*m*Fin/(p*2^s) = 2*100*12/(3*2^1)=400M
*/
ldr r0, =0x4C000004
ldr r1, =(92<<12)|(1<<4)|(1<<0)
str r1, [r0]
/* 一旦设置PLL, 就会锁定lock time直到PLL输出稳定
* 然后CPU工作于新的频率FCLK
*/
/* 设置内存: sp 栈 */
/* 分辨是nor/nand启动
* 写0到0地址, 再读出来
* 如果得到0, 表示0地址上的内容被修改了, 它对应ram, 这就是nand启动
* 否则就是nor启动
*/
mov r1, #0
ldr r0, [r1] /* 读出原来的值备份 */
str r1, [r1] /* 0->[0] */
ldr r2, [r1] /* r2=[0] */
cmp r1, r2 /* r1==r2? 如果相等表示是NAND启动 */
ldr sp, =0x40000000+4096 /* 先假设是nor启动 */
moveq sp, #4096 /* nand启动 */
streq r0, [r1] /* 恢复原来的值 */
bl main
halt:
b halt
三、串口的使用
内存是和buffer进行交互的。
串口初始化代码和实现基本函数
#include "s3c2440_soc.h"
/* 115200,8n1 */
void uart0_init()
{
/* 设置引脚用于串口 */
/* GPH2,3用于TxD0, RxD0 */
GPHCON &= ~((3<<4) | (3<<6));
GPHCON |= ((2<<4) | (2<<6));
GPHUP &= ~((1<<2) | (1<<3)); /* 使能内部上拉 ,一开始处于高电平状态*/
/* 设置波特率 */
/* UBRDIVn = (int)( UART clock / ( buad rate x 16) ) –1
* UART clock = 50M
* UBRDIVn = (int)( 50000000 / ( 115200 x 16) ) –1 = 26
*/
UCON0 = 0x00000005; /* PCLK,中断/查询模式 */
UBRDIV0 = 26;
/* 设置数据格式 */
ULCON0 = 0x00000003; /* 8n1: 8个数据位, 无较验位, 1个停止位 */
/* */
}
int putchar(int c)
{
/* UTRSTAT0 */
/* UTXH0 */
while (!(UTRSTAT0 & (1<<2)));
UTXH0 = (unsigned char)c;
}
int getchar(void)
{
while (!(UTRSTAT0 & (1<<0)));
return URXH0;
}
int puts(const char *s)
{
while (*s)
{
putchar(*s);
s++;
}
}
main函数
#include "s3c2440_soc.h"
#include "uart.h"
int main(void)
{
unsigned char c;
uart0_init();
puts("Hello, world!\n\r");
while(1)
{
c = getchar();
if (c == '\r')
{
putchar('\n');//回到行首部,不自动换行,我们可以增加输出一个\n
}
if (c == '\n')
{
putchar('\r');//输出一个字符串,换行后没有回到行首部,我们增加一个\r
}
putchar(c);
}
return 0;
}
问题:能不能依据printf的原理,写一个简易的用于裸机程序调试的my_printf函数呢?
好处:1)my_printf函数在单片机、嵌入式芯片裸机调试过程中非常方便。
2)my_printf函数可以帮你打印寄存器的值、变量的值、打印字符串等。
依据:函数调用参数是使用堆栈来实现的
printf的声明
int printf(const char *format, ...);
format:固定参数
... :可变参数(变参)
自动确定可变参数
#include <stdarg.h>
va_list p;
va_start(p,fmt );
va_arg( p, int);
va_end( p );
vc6.0中的stdarg.h
typedef char * va_list;
//当sizeof(n)=1/2/4时,_INTSIZEOF(n)等于4
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
/*
va_start(p, format ) ( p = (char *)&format + _INTSIZEOF(format) )
( p = (char *)&format + _INTSIZEOF(char *) )
( p = (char *)&format + 4 )
*/
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_arg(ap,t) (ap = ap + _INTSIZEOF(t), *(t *)(ap - _INTSIZEOF(t)))
#define va_arg(ap,t) (*(t *)(ap = ap + _INTSIZEOF(t), ap - _INTSIZEOF(t)))
逗号表达式,依次求值,但是最后的结果是最后一个表达式的值
/*
#define va_end(ap) ( ap = (char *)0 )
*/
#define va_end(ap) ( ap = (va_list)0 )