怎麼看待今年出現了很多非專業但是需要干嵌入式或單片機工程的人
///插播一條:我自己在今年年初錄製了一套還比較系統的入門單片機教程,想要的同學找我拿就行了免費的,私信我就可以哦~點我頭像黑色字體加我地球呺也能領取哦。最近比較閒,帶做畢設,帶學生參加省級或以上比賽///
0.緒論
對於經過系統培訓的開發者.單片機或SoC的驅動開發,不管是使用各種庫還是直接上寄存器,都不成問題.
可很多非專業但是需要干嵌入式或單片機工程的人,比如機械,車輛工程,物理,或是其他的一些專業.有時候這些學生需要搞比賽,做項目,不可避免的要用到一些單片機(由於種種原因,現在幾乎都會首選STM32).但是缺乏系統訓練的學生往往無法看懂寄存器版本的例程,或是別人的開源項目.自己寫的話更是不知道如何開始.或者編譯完成後總是出現莫名的問題.這給大家帶來了極大的困難.
同時網際網路上大部分教程都是轉載來轉載去,各種差異和版本都有.很多人即使看過了也是一頭霧水.所以應一個同學要求,大概寫一下寄存器的一些操作.
本教程將會使用"學生用戶體量龐大"的STM32F1xx系列的單片機作為例子.但是不必擔心.所有的寄存器操作都是共通的.並不會有本質的差異.希望你能快速閱讀完並且理解完,然後查閱自己需要的資料.不管是什麼東西,這種方式都是通用的.
嵌入式軟體開發具有一個比較龐大的知識體系.限於作者的時間和水平,本文不可能講太多東西.但是如果你只是因為不會寄存器開發而陷入瓶頸,那麼本文將會有較大幫助(畢竟這個是寫文章的目的).
理解本文需要一些基礎,大概包括: c/c++,一些數學,計算機基礎知識.大多數理工類專業都會有相關的課程的.如果確實存疑可以即時搜索.
讓我們先記住開發的正確方式: 摘抄借鑒,修改糅合,以實現功能為目的,以別人的代碼為基礎.
只要不涉及什麼智慧財產權的話,這樣做是完全沒有問題的.畢竟不需要把很多基礎性的東西寫來寫去.所以請大膽的找開源項目,儘可能在基礎上改,而不是從零開發.不廢話了,開始正事.
1.數學:數制,進位換算
數制也稱為「計數制」,是用一組固定的符號和統一的規則來表示數值的方法。任何一個數制都包含兩個基本要素:基數和位權. [1]任何一個數字都能這樣表示
計算機常用2進制.就是只有1和0的數字.其中1一般認為是高電平表示true,邏輯真值, 0一般是低電平, false,邏輯假值.
定理:在任意進位下,不一定所有的有理數都可以使用有限位數的小數形式表示.
比如十進位下的0.1就是二進位的無限不循環小數.上面那個例子也是.
著名的 IEEE754 float浮點數標準導致的bug:在很多語言中, 0.1+0.2≠0.3
就是因為0.1是二進位無限循環小數的原因.但是存儲器位寬不能是無窮的.所以產生捨入誤差.
在瀏覽器中按下F12進入開發者模式,嘗試JavaScript下的浮點數精度bug
所以在很多項目中,為了實現當兩個值相等時觸發什麼函數,往往不會直接寫相等,而是兩者的差值小於多少時即生效
floata,b;........if(a==b){
//這種寫法不建議}........if(abs(a-b)0.00001){
//一般這麼寫}
二進位與十/十六進位的轉換
剛才那個方法就可以直接算.還有其他算法這裡不講.先讓我貼一個表格:
BIN
DEC
HEX
0000
0
0
0001
1
1
0010
2
2
0011
3
3
0100
4
4
0101
5
5
0110
6
6
0111
7
7
1000
8
8
1001
9
9
1010
10
A
1011
11
B
1100
12
C
1101
13
D
1110
14
E
1111
15
F
BIN是二進制, DEC是十進制, HEX是十六進制.都是英語簡寫.
十六進位和二進位可以直接換算.方法是每四位二進位看作一個十六進位
比如
0110 1101 1011 1001
6 D B 9
轉換表背過的話讀代碼快些.因為一般情況下,為了讓一行代碼看的不至於太長,人們會用十六進位代表二進制.尤其是對於擁有32位cortex-M3內核的STM32F1系列單片機,一次寫一個三十二位數屬實太冗長.
c/c++中,默認寫的數字都是十進制.二進位應該是0b開頭,比如0b00101100,而十六進位是0x開頭,比如0x3C.
//一般這麼寫GPIOB->CRL&=0x00440000;//這麼寫就不太美觀了GPIOB->CRL&=0b00000000010001000000000000000000;
數學差不多了.開始正文.
2. c/c++語言基礎
a+b; //加法
a-b; //減法
a*b; //乘法
a/b; //除法,所有計算需要注意整型(整數)和浮點型(小數)的運算區別.如有疑問自行搜索
a%b; //求模.就是小學學的余數. 14÷4=3 ... 2 這里 14mod4=2, 14/4=3. float(14)/4=3.5f
a</左移.將a看為二進位數,整個向左移動b位.比如 00000110<就是 00011000.當溢出的時候會發生什麼呢?
a>>b; //右移.和上面一樣的功能.
a&b; //按位求與(AND),比如 11010010
// & 01010011
// ------------
// 01010010
a|b; //按位取或(OR)
~a; //按位取非(NOT)
!a; //邏輯非(注意和上面的區別)
c+=a; //相當於 c=c+a;其他算符同理.
重點看左右移和位操作(與,或,非等).
3.我們配寄存器(register)到底是在配置什麼
首先,你的最終目的都是使用單片機的GPIO(general pin input & output)讀取/輸出一個高電平還是低電平.不管是諸如I2C, SPI的通信,還是按鍵讀取,亮燈報警,說到底都是高低電平的控制或探測.
ADC輸入的是模擬(Analog)信號,但是會被轉化為數字(Digital)信號,一樣是高低電平.這裡暫且不談
外設,時鍾,或者一些功能的使能及配置一樣是通過寄存器的.原理相似.畢竟晶片集成電路也是電路,而且是數字電路.暫時不深入.
所以,為了讓某一個Pin輸出電平,或者使能一個通道,我們可以用0或者1實現.
但是代碼終歸是代碼,不是魔法.為了使需求生效,單片機將每一個需要控制的量,賦予一個地址.在電路層面上實現相關的功能綁定.用戶只需通過給這個地址去寫一個值,就相當於控制了需要控制的東西.易於計算,我們的32位處理器最大可以尋址4GB的內存空間.
庫函數和寄存器可以混著用嗎?
當然可以.本身使用庫函數的項目里可以直接引入寄存器的代碼.因為庫函數本身也用到了寄存器.但是寄存器要使用庫函數,需要先將庫函數導入到工程才行(編譯鏈的makefile文件里).當然都可以混著用.
7.這些沒問題了,但是那些OD開漏輸出,推輓輸出,浮空輸入,上拉輸入,都是什麼意思......