实际工作中很少会使用到汇编去编写嵌入式驱动,毕竟汇编太难,写出来也不好理解,大部分情况下都使用C语言去编写。只是在开始部分用汇编初始化一下C语言环境,比如初始化DDR、设置堆栈指针SP等。当这些工作都做完以后就可以进入C语言环境,也就是运行C语言代码,一般都是进入main函数。所以都是进入main函数,有两部分文件要做:
1、汇编文件
汇编文件只是用来完成C语言环境搭建的。
2、C语言文件
C语言文件就是完成我们的业务层代码的,其实就是我们实际要完成的功能。其实STM32也是这样的,只是我们在开发STM32的时候没有想到这一点,以STM32中启动文件startup_stm32f10x_hd.s这个汇编文件就是完成C语言环境搭建的,当然还有一些其他处理,比如中断向量表等。
第二:实验程序实现
在STM32中,启动文件startup_hd.s就是完成C语言环境搭建的,当然还有一些其他的处理。
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
;HeapConfiguration
;HeapSize(inBytes)<0x0-0xFFFFFFFF:8>
;
Heap_SizeEQU0x00000200
AREAHEAP,NOINIT,READWRITE,ALIGN=3
__heap_base
Heap_MemSPACEHeap_Size
__heap_limit
//省略掉部分代码
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT__main
IMPORTSystemInit
LDRR0,=SystemInit
BLXR0
LDRR0,=__main
BXR0
ENDP
代码分析:设置栈的大小,这里设置为0X400=1024字节。下面遇到的__initial_sp就是初始化SP指针。设置堆的大小,复位中断服务函数,STM32复位完成以后会执行中断服务函数。调用SystemInit()函数来完成其他初始化工作,会调用__main是库函数实现。
.global _start /* 全局标号 */
_start:
/* 进入 SVC 模式 */
mrsr0,cpsr
bicr0,r0,
orrr0,r0,
msrcpsr,r0//将r0的数据写入到cpsr_c中
ldr sp, =0X80200000 /* 设置栈指针 */
bmain/*跳转到main函数*/
这里我们可以设置处理器运行于SVC模式下,处理器模式的设置是通过修改CPSR程序状态寄存器来完成的。上面编写的start.s文件中却没有初始化DDR3的代码,但是却将SVC模式下的SP指针设置到了DDR3的地址范围中,这不会出问题吗?肯定不会的,DDR3肯定还是要初始化的,DCD数据包含了DDR配置参数,内部的Boot ROM会读取DCD数据中的参数完成DDR初始化的。
第三:C语言实验控制程序
C语言部分有两个文件件 main.c 和 main.h,main.h 里面主要是定义的寄存器地址,在 main.h里面输入代码:
//CCM相关寄存器地址
//相关寄存器地址
//GPIO1相关寄存器地址
在main.h中以宏定义的形式定义要使用到所有的寄存器,后面的数字就是其地址信息,比如CCM_CCGR0 寄存器的地址就是 0X020C4068,这个很简单,很好理解。main.c函数的具体实现。
//使能外设的所有时钟
void clk_enable(void)
{
CCM_CCGR0=0xffffffff;
CCM_CCGR1=0xffffffff;
CCM_CCGR2=0xffffffff;
CCM_CCGR3=0xffffffff;
CCM_CCGR4=0xffffffff;
CCM_CCGR5=0xffffffff;
CCM_CCGR6=0xffffffff;
}
//初始化LED对应的GPIO时钟
void led_init(void)
{
/* 1、初始化 IO 复用, 复用为 GPIO1_IO03 */
SW_MUX_GPIO1_IO03 = 0x5;
//配置GPIO1_IO03属性
SW_PAD_GPIO1_IO03 = 0X10B0;
//初始化GPIO,GPIO_IO03设置为输出
GPIO1_GDIR=0X0000008;
//设置GPIO1_IO03输出低电平,打开LED0
GPIO1_DR=0x0;
}
//打开对应的LED灯
void led_on(void)
{
//将GPIO1_DR 的 bit3 清零
GPIO1_DR &= ~(1<<3);
}
//关闭LED灯
void led_off(void)
{
GPIO1_DR |= (1<<3);
}
//短暂的延时函数
void delay_short(volatile unsigned int n)
{
while(--){}
}
//延时大约1ms的函数
void delay(volatile unsigned int n)
{
while(n--)
{
delay_short(0x7ff);
}
}
int main(void)
{
clk_enable(); /* 使能所有的时钟 */
led_init();/*初始化led*/
while(1)/*死循环*/
{
led_off();/*关闭LED*/
delay(500);/*延时大约500ms*/
led_on();/*打开LED*/
delay(500);/*延时大约500ms*/
}
return0;
}
利用Makefile文件可以进行编译,将对应的可执行文件,放到开发板上,可以看到LED大概500ms闪烁一次。
总结:利用C语言实现底层驱动的控制,要注意可执行程序放的位置,以及如何链接编译等。
审核编辑:郭婷
-
led
+关注
关注
242文章
23281浏览量
660990 -
Linux
+关注
关注
87文章
11306浏览量
209570 -
函数
+关注
关注
3文章
4332浏览量
62640
原文标题:Linux系统中利用C语言控制LED灯的实现
文章出处:【微信号:嵌入式开发爱好者,微信公众号:嵌入式开发爱好者】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
评论