ARM新一期第二天

一、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

三、串口的使用
uart
内存是和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:固定参数
...   :可变参数(变参)

在这里插入图片描述
printf

自动确定可变参数

#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 )
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值