實(shí)際工作中很少會(huì)使用到匯編去編寫嵌入式驅(qū)動(dòng),畢竟匯編太難,寫出來(lái)也不好理解,大部分情況下都使用C語(yǔ)言去編寫。只是在開(kāi)始部分用匯編初始化一下C語(yǔ)言環(huán)境,比如初始化DDR、設(shè)置堆棧指針SP等。當(dāng)這些工作都做完以后就可以進(jìn)入C語(yǔ)言環(huán)境,也就是運(yùn)行C語(yǔ)言代碼,一般都是進(jìn)入main函數(shù)。所以都是進(jìn)入main函數(shù),有兩部分文件要做:
1、匯編文件
匯編文件只是用來(lái)完成C語(yǔ)言環(huán)境搭建的。
2、C語(yǔ)言文件
C語(yǔ)言文件就是完成我們的業(yè)務(wù)層代碼的,其實(shí)就是我們實(shí)際要完成的功能。其實(shí)STM32也是這樣的,只是我們?cè)陂_(kāi)發(fā)STM32的時(shí)候沒(méi)有想到這一點(diǎn),以STM32中啟動(dòng)文件startup_stm32f10x_hd.s這個(gè)匯編文件就是完成C語(yǔ)言環(huán)境搭建的,當(dāng)然還有一些其他處理,比如中斷向量表等。
第二:實(shí)驗(yàn)程序?qū)崿F(xiàn)
在STM32中,啟動(dòng)文件startup_hd.s就是完成C語(yǔ)言環(huán)境搭建的,當(dāng)然還有一些其他的處理。
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
代碼分析:設(shè)置棧的大小,這里設(shè)置為0X400=1024字節(jié)。下面遇到的__initial_sp就是初始化SP指針。設(shè)置堆的大小,復(fù)位中斷服務(wù)函數(shù),STM32復(fù)位完成以后會(huì)執(zhí)行中斷服務(wù)函數(shù)。調(diào)用SystemInit()函數(shù)來(lái)完成其他初始化工作,會(huì)調(diào)用__main是庫(kù)函數(shù)實(shí)現(xiàn)。
.global _start /* 全局標(biāo)號(hào) */
_start:
/* 進(jìn)入 SVC 模式 */
mrsr0,cpsr
bicr0,r0,
orrr0,r0,
msrcpsr,r0//將r0的數(shù)據(jù)寫入到cpsr_c中
ldr sp, =0X80200000 /* 設(shè)置棧指針 */
bmain/*跳轉(zhuǎn)到main函數(shù)*/
這里我們可以設(shè)置處理器運(yùn)行于SVC模式下,處理器模式的設(shè)置是通過(guò)修改CPSR程序狀態(tài)寄存器來(lái)完成的。上面編寫的start.s文件中卻沒(méi)有初始化DDR3的代碼,但是卻將SVC模式下的SP指針設(shè)置到了DDR3的地址范圍中,這不會(huì)出問(wèn)題嗎?肯定不會(huì)的,DDR3肯定還是要初始化的,DCD數(shù)據(jù)包含了DDR配置參數(shù),內(nèi)部的Boot ROM會(huì)讀取DCD數(shù)據(jù)中的參數(shù)完成DDR初始化的。
第三:C語(yǔ)言實(shí)驗(yàn)控制程序
C語(yǔ)言部分有兩個(gè)文件件 main.c 和 main.h,main.h 里面主要是定義的寄存器地址,在 main.h里面輸入代碼:
//CCM相關(guān)寄存器地址
//相關(guān)寄存器地址
//GPIO1相關(guān)寄存器地址
在main.h中以宏定義的形式定義要使用到所有的寄存器,后面的數(shù)字就是其地址信息,比如CCM_CCGR0 寄存器的地址就是 0X020C4068,這個(gè)很簡(jiǎn)單,很好理解。main.c函數(shù)的具體實(shí)現(xiàn)。
//使能外設(shè)的所有時(shí)鐘
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對(duì)應(yīng)的GPIO時(shí)鐘
void led_init(void)
{
/* 1、初始化 IO 復(fù)用, 復(fù)用為 GPIO1_IO03 */
SW_MUX_GPIO1_IO03 = 0x5;
//配置GPIO1_IO03屬性
SW_PAD_GPIO1_IO03 = 0X10B0;
//初始化GPIO,GPIO_IO03設(shè)置為輸出
GPIO1_GDIR=0X0000008;
//設(shè)置GPIO1_IO03輸出低電平,打開(kāi)LED0
GPIO1_DR=0x0;
}
//打開(kāi)對(duì)應(yīng)的LED燈
void led_on(void)
{
//將GPIO1_DR 的 bit3 清零
GPIO1_DR &= ~(1<<3);
}
//關(guān)閉LED燈
void led_off(void)
{
GPIO1_DR |= (1<<3);
}
//短暫的延時(shí)函數(shù)
void delay_short(volatile unsigned int n)
{
while(--){}
}
//延時(shí)大約1ms的函數(shù)
void delay(volatile unsigned int n)
{
while(n--)
{
delay_short(0x7ff);
}
}
int main(void)
{
clk_enable(); /* 使能所有的時(shí)鐘 */
led_init();/*初始化led*/
while(1)/*死循環(huán)*/
{
led_off();/*關(guān)閉LED*/
delay(500);/*延時(shí)大約500ms*/
led_on();/*打開(kāi)LED*/
delay(500);/*延時(shí)大約500ms*/
}
return0;
}
利用Makefile文件可以進(jìn)行編譯,將對(duì)應(yīng)的可執(zhí)行文件,放到開(kāi)發(fā)板上,可以看到LED大概500ms閃爍一次。
總結(jié):利用C語(yǔ)言實(shí)現(xiàn)底層驅(qū)動(dòng)的控制,要注意可執(zhí)行程序放的位置,以及如何鏈接編譯等。
審核編輯:郭婷
-
led
+關(guān)注
關(guān)注
242文章
23355瀏覽量
663190 -
Linux
+關(guān)注
關(guān)注
87文章
11345瀏覽量
210392 -
函數(shù)
+關(guān)注
關(guān)注
3文章
4346瀏覽量
62971
原文標(biāo)題:Linux系統(tǒng)中利用C語(yǔ)言控制LED燈的實(shí)現(xiàn)
文章出處:【微信號(hào):嵌入式開(kāi)發(fā)愛(ài)好者,微信公眾號(hào):嵌入式開(kāi)發(fā)愛(ài)好者】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論