您好,歡迎進(jìn)入深圳市穎特新科技有限公司官方網(wǎng)站!
很多學(xué)習(xí)stm32的,為什么學(xué)習(xí)stm32他也不知道,我們所知道的就是各個(gè)論壇討論stm32的很多,而我們很多人之所以學(xué)習(xí)stm32是很多的淘寶賣家做了大量的圖片文字宣傳,于是我們經(jīng)不住誘惑就買了板子,然后我們就開始了我們的學(xué)習(xí)之旅。
在淘寶賣家的眼里有著齊全的入門資料是板子的最大的賣點(diǎn),于是當(dāng)我們拿到開發(fā)板的時(shí)候,我們感覺我們永遠(yuǎn)不能和別人說(shuō)自己熟悉stm32,因?yàn)槊撾x了網(wǎng)絡(luò)的資料我們什么都做不了,這是我們最害怕的事情。
今天我就就像在這里記錄下自己一無(wú)所有建立stm32工程的過(guò)程,是我自己的一個(gè)探索過(guò)程,同時(shí)也是大家互相交流的過(guò)程。
第一步:當(dāng)然是新建一個(gè)工程我把它命名為small(這個(gè)隨便你,青菜蘿卜各有所愛……)
第二部:就是選擇芯片的型號(hào)了,這個(gè)按照每個(gè)人手上的板子的不同就選擇不同的芯片型號(hào)。
選擇完了之后按確認(rèn),然后會(huì)出來(lái)一個(gè)對(duì)話框,是問(wèn)你要不要添加啟動(dòng)文件的,這個(gè)簡(jiǎn)單我們都是白手起家了,別人好不容易送你點(diǎn)東西我們當(dāng)然照單全收,直接點(diǎn)是。」。。。。。
點(diǎn)完是后我們的工程就是差不多建立好了,大家可以看到里面就一個(gè)代碼文件,是以.s結(jié)尾的,是一個(gè)啟動(dòng)文件里面的代碼全是匯編的,看了有點(diǎn)暈死。。。。,以后再說(shuō)吧這個(gè)。。。。
要不我們編譯了看看結(jié)果?
一串鳥文的錯(cuò)誤,看不怎么懂,但是好像是說(shuō)什么沒有main函數(shù)。想想也是啊,自己確實(shí)沒寫main函數(shù),要不我們自己建立一個(gè).c文件,然后寫一個(gè)main函數(shù)?說(shuō)做就做。。。。。
直接點(diǎn)擊file下面的新建圖標(biāo),然后寫一個(gè)名字保存,注意別忘保存好之后在工程里面“add files to group”,然后我們?cè)僮约簩懸粋(gè)空的main函數(shù),大家看看我做的對(duì)不對(duì)?
這下可以編譯了吧?
編譯有警告說(shuō)什么main函數(shù)的返回值必須是int。。。。不知道為什么?
百度看了下好像是編譯器和c語(yǔ)言標(biāo)準(zhǔn)規(guī)范的問(wèn)題,沒辦法那就修改下main函數(shù)的返回值吧,把前面的main前面的void變成int就好了。
編譯通過(guò)了。。。
要不我們接下來(lái)設(shè)置工程屬性看看?這個(gè)是很多教程中有的,我不想多少,大家自己找找吧。。。。
你看都可以仿真,哈哈那就說(shuō)明系統(tǒng)運(yùn)行起來(lái)了。。。。但是我們什么都看不到,接下來(lái)我們的任務(wù)就是想辦法點(diǎn)亮一個(gè)led燈。
首先我們要控制燈的話就要操作寄存器,還記得我們?cè)?1里面要操作P0口嗎?是用P0=0x00,這里面簡(jiǎn)單的說(shuō)下51里面操作IO口的原理,我們看到這里有一個(gè)P0,這個(gè)P0是哪里來(lái)的?顯然不像是int一樣是是c語(yǔ)言本身自帶的,也不是某一個(gè)變量是我們自己定的,其實(shí)這個(gè)是在reg52.h里面定義的,有圖有真相。
可以看到在我們一直使用reg52.h里面他做了這樣一件事情,就是把我們的真實(shí)物理地址是0x90的這個(gè)P1寄存器和P1這個(gè)代名詞相互聯(lián)系了,其實(shí)P1只是一個(gè)代名詞,假如我在reg52.h里面修改 把sfr P1 = 0x90;修改為sfr XX = 0x90;這樣也是可以用的,只不過(guò)下一次你要對(duì)P1口進(jìn)行操作的時(shí)候要寫XX=0x00;了,所以為了好記我們就把名字取成P1,現(xiàn)在我們知道了51的原理,我們可以依葫蘆畫瓢來(lái)操作stm32的GPIO,先不管我們要操作什么寄存器,我們要接解決的第一個(gè)問(wèn)題怎么使用c語(yǔ)言操作單片機(jī)中知道絕對(duì)物理地址的寄存器,比如我們通過(guò)查資料RM0008的179頁(yè)知道了關(guān)于IO操作的一個(gè)寄存器GPIOA_CRL的絕對(duì)地址是0x40010800+0x00(其中0x40010800是起始地址,0x00是偏移地址),接下來(lái)我們?cè)趺床僮魉兀坑?sfr?好像sfr是51匯編特有的指令,在arm里面沒有。。。這時(shí)候我們是否想到c語(yǔ)言的一個(gè)和地址緊密相關(guān)的內(nèi)容----指針,我們?cè)谏险n的時(shí)候知道指針的本質(zhì)就是地址,這樣我們是否可以通過(guò)它來(lái)把實(shí)際的物理地址和c語(yǔ)言變量建立關(guān)系呢?首先我們要把絕地地址變?yōu)橹羔樧兞?,肯定是強(qiáng)制類型轉(zhuǎn)換了(int*(0x40010800+0x00))通過(guò)這一步我們已經(jīng)有一個(gè)int類型的指針,這個(gè)指針指向的地址就是我們GPIOA_CRL的絕對(duì)地址(0x40010800+0x00),有了指針之后我們要取變量,那么很簡(jiǎn)單只要一個(gè)簡(jiǎn)單的*取變量運(yùn)算符就可以了(int*(0x40010800+0x00)),這下變量有了那么我們是不是需要給變量取一個(gè)名字?
那就這樣#define GPIOA_CRL *((int*)(0x40010800+0x00)) 好了完成了我們終于可以再c語(yǔ)言的環(huán)境中操作我們的寄存器了,接下來(lái)我們只要給GPIOA_CRL 這個(gè)變量賦值就是我們?cè)诮oGPIOA_CRL 這個(gè)寄存器賦值,先休息下再說(shuō)。。。。。
這篇文章其實(shí)我是一邊寫代碼做測(cè)試一邊寫的,就在上面我想要控制IO的時(shí)候花了好長(zhǎng)的時(shí)間,就是因?yàn)樽约旱牟蛔屑?xì)吧!犯了幾個(gè)小錯(cuò)誤。先看我的最終代碼。
代碼非常的簡(jiǎn)單,但是為了這幾行代碼花了我好久的時(shí)間,我已經(jīng)在代碼后面寫了注釋了,具體的怎么來(lái)的讓我婉婉道來(lái),首先是上面那幾行的define的機(jī)構(gòu)我在上面已經(jīng)介紹過(guò)了,具體的地址是怎么知道的?下面我來(lái)簡(jiǎn)單的說(shuō)下,在stm32的
RM0008
Reference manual
STM32F101xx, STM32F102xx, STM32F103xx, STM32F105xx
and STM32F107xx advanced ARM-based 32-bit MCUs
這個(gè)開發(fā)文檔中的44頁(yè)內(nèi)存映射表,如下圖
我截圖的只是上半部分,還有下半部分,在下半部分我們可以看到
從這里可以看到和GPIOA相關(guān)的寄存器的起始地址是0x40010400所以代碼中的一開始的基址是這個(gè),然后我們需要知道不同的寄存器的偏移地址,這個(gè)是在后面的跳轉(zhuǎn)的鏈接可以看到的,跳轉(zhuǎn)到179頁(yè),偏移地址的表格
這樣的話上面的幾個(gè)define的計(jì)算也就水落石出了。
這里簡(jiǎn)單的說(shuō)下自己當(dāng)時(shí)犯的一個(gè)錯(cuò)誤。我一開始寫的#define GPIOA_CRL *((int*)0x40010800+0x00) 是這樣的,調(diào)試后死活不是我想要的工作效果,后來(lái)花了好大的力氣才想起來(lái)原來(lái)是宏定義的括號(hào)的問(wèn)題,大家仔細(xì)比對(duì)下我在代碼中的寫的和我上面的寫法,發(fā)現(xiàn)什么端倪沒?#define GPIOA_CRL *((int*)(0x40010800+0x00)) 看到紅色的括號(hào)沒?就是因?yàn)橐粋(gè)小小的括號(hào)耽誤了很長(zhǎng)時(shí)間。
花了這么長(zhǎng)的時(shí)間我們終于可以操作IO口了,那怎么操作呢?在學(xué)過(guò)51的人的眼里那是很簡(jiǎn)單的,就是直接把我們要IO口輸出的值送到數(shù)據(jù)寄存器中不就好了,但是畢竟他是高級(jí)的stm32,所以要復(fù)雜點(diǎn),首先我們要開啟GPIOA的端口時(shí)鐘,這也許大家會(huì)疑惑了,怎么還和時(shí)鐘有關(guān)系了。。。。還是看資料吧!
可以看到GPIOA是掛載在AHB2總線上面的,他們都有自己的時(shí)鐘信號(hào)的控制端,這是由stm32的機(jī)構(gòu)決定的,我想之所以這樣做,一方面可以降低系統(tǒng)功耗,讓工作的模塊的時(shí)鐘使能,不工作的就不使能,其實(shí)這里的時(shí)鐘信號(hào)就好比是模塊的心臟一樣,只有先讓他工作了我們才可以去對(duì)他進(jìn)行操作,這就是代碼上 RCC_APB2ENR=0x00000004;//開啟GPIOA的端口時(shí)鐘這一句的作用,我嘗試過(guò),假如去掉這一句話的話,即使我后面對(duì)寄存器賦值了,也是沒有作用的。所以這一句很重要,而且與下面的順序是不好交換的。接下來(lái)就是設(shè)置GPIO的工作方式什么輸入輸出 模式之類的,對(duì)于只學(xué)過(guò)51的人來(lái)說(shuō)有點(diǎn)新鮮感覺,如果學(xué)過(guò)其他高級(jí)點(diǎn)單片機(jī)的 估計(jì)已經(jīng)習(xí)以為常了,就那么回事,具體的寄存器的每一位我就多說(shuō)了,直接看stm32f10XXXX參考手冊(cè)的113頁(yè)上滿寫的很清楚了。
這里再順便解釋下下我看到的一個(gè)現(xiàn)象,先看文檔
從這里面我們知道任何IO在復(fù)位之后都處于浮空輸入狀態(tài),這是PDF上說(shuō)的通過(guò)我的代碼大家看到我只是改變GPIOA0這位的狀態(tài)所以其他IO口應(yīng)該還是浮空輸入的模式,但是實(shí)際上是的嗎?
看仿真截圖:
大家可以看到其他幾個(gè)口還是聽話的就是PA12 PA13 PA14 PA15不怎么對(duì)勁,怎么回事呢?一開始我也疑惑,后來(lái)突然想起來(lái)了,這不是我們仿真用的jtag口嗎?這樣的話就對(duì)了,于是為了驗(yàn)證我的想法,我查看jtag用的其他IO口的情況,都不是默認(rèn)的浮空輸入模式,這樣的話就應(yīng)該是這個(gè)原因了。(提醒大家一下以后設(shè)計(jì)硬件的時(shí)候盡量避免使用jtag口,如果實(shí)在避免不了的話在設(shè)計(jì)程序的時(shí)候就要注意關(guān)閉jtag模式釋放那幾個(gè)IO口,在此做一個(gè)友情提醒因?yàn)楸豢舆^(guò)幾次。。。)
代碼寫完了,然后編譯下載,不出意外的話就可以看到PA0上面接的led燈亮了,這是必然的結(jié)果,這一次入門教程也就差不多了。。。,謝謝!
相關(guān)代碼的下載鏈接是:http://files.cnblogs.com/51mcu/small_9.20.zip
如果有什么錯(cuò)誤的話歡迎批評(píng)指正!
這篇文章是我轉(zhuǎn)載的,雖然時(shí)間很久了,不過(guò)真的感謝這篇文章,解決了我很多的疑問(wèn)和困惑。
明天是美好的,每天進(jìn)步一點(diǎn)點(diǎn),經(jīng)過(guò)時(shí)間的累積那也是種巨大的收獲。
一分辛苦一分才,我相信自己的努力。
掃碼關(guān)注我們
傳真:0755-82591176
郵箱:vicky@yingtexin.net
地址:深圳市龍華區(qū)民治街道民治大道973萬(wàn)眾潤(rùn)豐創(chuàng)業(yè)園A棟2樓A08