
本教程視頻版已經(jīng)發(fā)布在CW32生態(tài)社區(qū)視頻號(hào)與B站號(hào)上:
https://space.bilibili.com/3493144165354211/lists/1803525?type=season
Ⅰ、模塊移植
1.CW32F030的MCU運(yùn)用:此一步驟沒有太多好講的,涉及到自身個(gè)人毅力,學(xué)習(xí)時(shí)間的長短等不可控因素;需自身去學(xué)習(xí),但其實(shí)在此項(xiàng)目中沒用多少外設(shè),能熟練運(yùn)用GPIO,EXTI,USART,SPI就夠了(IIC是模擬的);如果沒有基礎(chǔ)的話最好集中學(xué)習(xí)。
2.OLED屏幕驅(qū)動(dòng):
前面說了此屏幕想讓它顯示我們要顯示的數(shù)據(jù),需通過IIC協(xié)議向其發(fā)送命令設(shè)置好寄存器,再通過發(fā)送數(shù)據(jù)對(duì)OLED的顯存進(jìn)行操作也就是讓相應(yīng)的像素點(diǎn)點(diǎn)亮就行了;
下面來詳解一下如何從0到顯示一個(gè)’1‘出來:
我們所使用的是模擬IIC,意思就是使用GPIO,通過置1置0來模擬IIC中的高低電平,通過改變置1置0的延時(shí)時(shí)間從而改變IIC的速率;
如圖1:

圖1這個(gè)結(jié)構(gòu)描述了IIC通訊時(shí)的基本結(jié)構(gòu),包含起始位,8位數(shù)據(jù),應(yīng)答位,結(jié)束位;此結(jié)構(gòu)也是IIC發(fā)送一個(gè)8位數(shù)據(jù)時(shí)需要遵循的結(jié)構(gòu),這也是IIC的特性;我們需要的是使用我們的GPIO通過置1置0以及延時(shí)來模擬此IIC的結(jié)構(gòu),也就是起始位,8位數(shù)據(jù),應(yīng)答位,結(jié)束位。
圖2:

如圖2想要使用我們的GPIO通過置1置0以及延時(shí)來模擬此IIC的結(jié)構(gòu),那么就要了解起始位,8位數(shù)據(jù),應(yīng)答位,結(jié)束位的具體結(jié)構(gòu);可以看到上述協(xié)議幀從左往右:START是起始位,想使用GPIO模擬此時(shí)序只需讓模擬的SDA,SCL全置1然后讓SDA置0,SCL暫不用管,延時(shí)(或不用延時(shí))一會(huì),再將SCL置0就行了,隨后這么一寫,封裝成一個(gè)函數(shù)那不就成了嗎:

結(jié)束位也是一樣只需讓模擬的SDA,SCL全置0然后讓SCL置1,SDA暫不用管,延時(shí)(或不用延時(shí))一會(huì),再將SDA置1就行了:

應(yīng)答信號(hào)最為簡單,因?yàn)椴簧婕暗阶x取數(shù)據(jù)所以不需要向?qū)Ψ奖砻魑曳接袥]有讀取到數(shù)據(jù):

寫一個(gè)字節(jié)就復(fù)雜一點(diǎn)點(diǎn),需要循環(huán)8個(gè)SCL與SDA,每一個(gè)循環(huán)都表達(dá)一位的數(shù)據(jù),也就是向外輸出8位,發(fā)送一個(gè)字節(jié)數(shù)據(jù):

上述函數(shù)一個(gè)一個(gè)封裝起來就相當(dāng)于是模擬出了起始位,8位數(shù)據(jù),應(yīng)答位,結(jié)束位,分別按順序調(diào)用這些個(gè)函數(shù)就是完整的IIC協(xié)議了;要注意的是OLED_SDA_OUT();上述函數(shù)中此函數(shù)是相當(dāng)于將IO口配置為推挽輸出的,在當(dāng)前環(huán)境下,此函數(shù)只需要配置一次就行,因?yàn)樵谛枰x取數(shù)據(jù)時(shí)才需要將IO口配置為輸入模式。
圖3:

如圖3在我們模擬出了起始位,8位數(shù)據(jù),應(yīng)答位,結(jié)束位后,分別按順序調(diào)用這些個(gè)函數(shù)就是完整的IIC協(xié)議,上述就是兩個(gè)實(shí)例,上面將起始位,8位數(shù)據(jù),應(yīng)答位,結(jié)束位按一個(gè)順序分別排列,其中發(fā)送的數(shù)據(jù)0X78,0X00,0X40分別代表OLED的地址,即將寫入命令,即將寫入數(shù)據(jù)三種意思;這些數(shù)據(jù)已經(jīng)不屬于IIC協(xié)議的范疇了,不同但符合IIC協(xié)議的設(shè)備這幾個(gè)值是不一樣的;通過上面的函數(shù)寫入命令,下面的函數(shù)寫入數(shù)據(jù),OLED就能正常接收到我們發(fā)送過去的數(shù)據(jù)了。
圖4:

如圖4:上面我們說過使用發(fā)送命令函數(shù)對(duì)一些相應(yīng)的寄存器進(jìn)行設(shè)置后,再使用發(fā)送數(shù)據(jù)函數(shù)就對(duì)顯存進(jìn)行操作就行,在我們使用GPIO模擬出了起始位,8位數(shù)據(jù),應(yīng)答位,結(jié)束位后,也封裝出了發(fā)送命令函數(shù)和發(fā)送數(shù)據(jù)函數(shù);現(xiàn)在使用發(fā)送命令的函數(shù)向OLED的寄存器進(jìn)行一些設(shè)置,具體要設(shè)置啥得自己翻譯去,網(wǎng)上找找肯定也有中文注釋,大概就是設(shè)置一些像范圍,是否反向顯示等等;進(jìn)行完這一步后,就來到了最終的發(fā)送數(shù)據(jù)來顯示我們想要的’1‘了。
圖5:

如圖5這個(gè)函數(shù)是把我們想要顯示的字符與我們向括號(hào)填入的字符聯(lián)系起來的函數(shù),因?yàn)榧僭O(shè)我們填入’1‘這個(gè)字符進(jìn)去,OLED是不認(rèn)識(shí)的,我們需要給OLED提供一個(gè)字庫,F(xiàn)8X16[c*16+i]就描述的是8*16像素點(diǎn)大小的字庫,里面描述了0-9分別應(yīng)該怎么顯示,字庫包含的數(shù)據(jù)與我們要顯示的數(shù)據(jù)是一 一對(duì)應(yīng)的,字庫就是OLED的語言,’1‘屬于我們?nèi)祟惖恼Z言。
圖6:

就像這個(gè)0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,這是OLED認(rèn)識(shí)的’1‘,我們將此6個(gè)數(shù)據(jù)發(fā)往OLED那么OLED就會(huì)在屏幕上顯示為’1‘,中間涉及到一個(gè)取模的過程;仔細(xì)看看可以看出將此6個(gè)字節(jié)表達(dá)的數(shù)據(jù)按順序?qū)懗?進(jìn)制,2進(jìn)制里所有的’1‘連在一起其實(shí)就可以看出里面的數(shù)據(jù)表達(dá)的就是我們?nèi)怂J(rèn)識(shí)的向右倒地的’1‘。
至此如何從0到顯示一個(gè)’1‘出來結(jié)束。
3.MPU6050陀螺儀驅(qū)動(dòng):
陀螺儀的IIC驅(qū)動(dòng)與OLED差不多,起始位,8位數(shù)據(jù),應(yīng)答位,結(jié)束位都是共用的,區(qū)別在于(1)多了一個(gè)讀取數(shù)據(jù)的函數(shù),(2)需要等待應(yīng)答信號(hào),(3)需要發(fā)送應(yīng)答或不應(yīng)答信號(hào),(4)以及上述講的陀螺儀的地址,寫入命令與寫入數(shù)據(jù)的差別。
圖7:

如圖7此函數(shù)描述了如何從SDA引腳讀取8位數(shù)據(jù),與IIC的發(fā)送8為數(shù)據(jù)類似,都是需要循環(huán)8次;區(qū)別在(1)需要提前MPU_SDA_IN();也就是將SDA引腳設(shè)置為輸入,(2)需要定義一個(gè)8位局部變量每讀一位數(shù)據(jù)向左偏移一位以存儲(chǔ)起來,循環(huán)8次正好儲(chǔ)存一整字節(jié),(3)在接收完一個(gè)字節(jié)后,不論是不是接收到了正確的數(shù)據(jù),一定得發(fā)送是否應(yīng)答的信號(hào)。
圖8.1,8.2,8.3



第一張圖是上面所說的描述了需要等待對(duì)方是否應(yīng)答,因?yàn)樵诖朔N通訊模式下需要反復(fù)確認(rèn)對(duì)方是不是在線,有沒有正確接收到發(fā)過去的數(shù)據(jù);第二張與第三張描述了發(fā)送應(yīng)答信號(hào)或是不應(yīng)答信號(hào),應(yīng)答對(duì)方設(shè)備就會(huì)認(rèn)為你是正常的會(huì)繼續(xù)發(fā)數(shù)據(jù),不應(yīng)答直接結(jié)束通訊。
到此之上都是屬于IIC的協(xié)議層接下來就是設(shè)備獨(dú)有的了。
圖9:


圖9此兩個(gè)函數(shù)是融入了MPU6050的特性的,從這里就可以看出MPU與OLED使用IIC的不同,OLED發(fā)送8位數(shù)據(jù)0X78,0X00,0X40分別代表OLED的地址,即將寫入命令,即將寫入數(shù)據(jù)三種意思;MPU則是((MPU_ADDR<<1)|0),((MPU_ADDR<<1)|1)分別代表寫命令和讀數(shù)據(jù),兩者使用IIC的區(qū)別一目了然且都完美符合IIC協(xié)議;在進(jìn)行完上面的操作后,就是對(duì)設(shè)備的相應(yīng)寄存器進(jìn)行設(shè)置,設(shè)置好后就可以讀數(shù)據(jù)了。
圖10:

如圖10此函數(shù)是最終使用IIC的最關(guān)鍵一步,對(duì)相應(yīng)的寄存器進(jìn)行設(shè)置,上面有中文注釋是最好的了,看看中文注釋大概也能明白每個(gè)及寄存器都是怎么設(shè)置的;在調(diào)用完此函數(shù)之后:
圖11:


如圖11調(diào)用此兩個(gè)函數(shù)傳入6個(gè)指針就能得到三軸的角速度與加速度了,使用變量保存下來這就是原始值了,就可以用這原始值再做處理得到三軸對(duì)地角度(使用一階互補(bǔ)過濾+卡爾曼濾波)去用;或者是我下面要介紹的方法(使用內(nèi)部DMP庫):
1.首先要獲取DMP庫,這個(gè)庫比較常見,也可以在我這個(gè)工程中復(fù)制過去:

添加里面的兩個(gè)的源文件到工程中,再指定頭文件路徑到此文件夾;
2.分別點(diǎn)開兩個(gè)源文件可以看到一些毫秒延時(shí),這部分可能需要你用你定義的毫秒延時(shí)函數(shù)替換,這是DMP庫需要用到的;
3.在定義好了上述所有的讀一個(gè)字節(jié)和寫一個(gè)字節(jié)后,還需要自己去實(shí)現(xiàn)兩個(gè)函數(shù):
uint8_t MPU_Write_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf);
uint8_t MPU_Read_Len(uint8_t addr,uint8_t reg,uint8_t len,uint8_t *buf);這兩個(gè)函數(shù)就是連續(xù)寫連續(xù)讀,是DMP庫需要用到的,最好將一下幾個(gè)文件全都移植過去,不然極易出錯(cuò):

最后全部函數(shù)定義好后,調(diào)用uint8_t mpu_dmp_get_data(float *pitch,float *roll,float *yaw)函數(shù)就可以直接得到三軸對(duì)地的角度了,就可以直接使用了。
4.超聲波模塊驅(qū)動(dòng):以下的模塊就都比較簡單了,使用GPIO與TIM就行:

從上面的時(shí)序圖就可以看到超聲波模塊是怎么使用的了:
1.初始化發(fā)射與接收引腳,初始化定時(shí)器,并在初始化時(shí)讓發(fā)射引腳置0;
2.將發(fā)射引腳置1延時(shí)15us在置0,觸發(fā)模塊內(nèi)部循環(huán)發(fā)出超聲波脈沖;
3.將接收中斷開啟,觸發(fā)方式為上伸沿和下降沿,在中斷觸發(fā)時(shí)檢測為高電平打開定時(shí)器開始計(jì)數(shù);
4.當(dāng)中斷再次被觸發(fā)時(shí)檢測電平為低時(shí)關(guān)閉定時(shí)器,保留計(jì)數(shù),清除計(jì)數(shù)值;
5.根據(jù)設(shè)置的重裝載值和預(yù)分頻值求出每一次的時(shí)間乘上計(jì)數(shù)值就是聲音在模塊與障礙物運(yùn)動(dòng)的時(shí)間,聲速340m/s求出距離。
5.蜂鳴器模塊驅(qū)動(dòng):
常見的蜂鳴器頻率為2700HZ,有不同的可問問賣家或數(shù)據(jù)手冊;
1.初始化TIM,使 主頻/(預(yù)分頻系數(shù)*自動(dòng)重裝載值) 大概等于2700就行了;
2.設(shè)置蜂鳴器占空比,使能定時(shí)器就可以響了,改變占空比,就可以改變響度。
6.紅外傳感器使用:
初始化IO口,開啟下降沿中斷就行,觸發(fā)中斷后就在中斷里處理就行。
Ⅱ、功能模塊學(xué)習(xí)
1.語音模塊選型及其編程方法:
選型的話選擇了一款常見的可編程語音模塊ASRPRO,32位的MCU,RISC內(nèi)核架構(gòu),外圍電路只需要加上麥克風(fēng)和喇叭;
(1)編譯環(huán)境:直接搜索天問Block下載就行

(2)選擇主板,檢查串口連接:通過ASRPRO的串口0下載程序,PB5是TX,PB6是RX

(3)界面說明:

(4)打開范例程序,設(shè)置編譯下載模式:

(5)編譯下載范例程序,隨后下載成功后按照需要的修改修改隨后重新生成模型下載即可:


2.藍(lán)牙模塊使用及其適配軟件:
使用的藍(lán)牙模塊是BT04-E,支持BLE,SPP;傳輸穩(wěn)定,距離遠(yuǎn),且官方有適配的軟件,使用串口通訊就行
其中的智能小車組件剛好可以用:

只需要使用USB轉(zhuǎn)TTL連接上此藍(lán)牙的串口,默認(rèn)藍(lán)牙串口波特率為9600,通過點(diǎn)擊上述的按鈕在電腦上打印出來就知道每個(gè)按鈕對(duì)應(yīng)什么數(shù)值了,使用這些數(shù)值,配合switch語句點(diǎn)擊不同按鈕,執(zhí)行不同的小車向前向后語句,就能輕松使用了。
3.思考避障模塊在程序中的邏輯嵌入:
此邏輯在程序中才能體現(xiàn),后續(xù)在程序加上就行。
4.麥克風(fēng)陣列的驅(qū)動(dòng)與使用:
在此項(xiàng)目中需要的功能是檢測聲源的方位,驅(qū)動(dòng)主控Maix bit是基于嘉楠堪智科技的邊緣智能計(jì)算芯片K210(RISC-V架構(gòu) 64位雙核)設(shè)計(jì)的一款AIOT開發(fā)板;
配合6+1麥克風(fēng)陣列就能檢測到6個(gè)方向的聲源大小,具體步驟:
1.配置開發(fā)環(huán)境:
(1).安裝 USB 驅(qū)動(dòng) - Sipeed Wiki
(2).MaixPy IDE 安裝與使用 - Sipeed Wiki
2.對(duì)聲源定位例程略微修改下,給即將發(fā)出的數(shù)據(jù)限定一個(gè)最小值:

3.使用下載軟件uPyLoader將固件中的main.py替換成我們所寫的main.py(由聲源定位改名而來),就可以使開機(jī)直接執(zhí)行我們所修改的程序。

Ⅲ、硬件設(shè)計(jì)
硬件設(shè)計(jì)沒有太多好講的,沒有涉及到多少模電數(shù)電的多少知識(shí),這里挑選一些注意點(diǎn)講講:

此圖畫的有些隨意,但這么畫主要就是想看起來功耗分配的清晰,有哪些模塊,每個(gè)模塊都想在不用時(shí)使用PMOS與NMOS的結(jié)構(gòu)來斷電實(shí)現(xiàn)無功耗;
1.12V轉(zhuǎn)5V按照數(shù)據(jù)手冊來畫原理圖就行,標(biāo)準(zhǔn)的12轉(zhuǎn)5V,但是手冊描述的0-15V時(shí)電感大小為33uH,0-30V時(shí)電感為47uH,于是將電感改成了47uH。
2.USB轉(zhuǎn)串口主要是為了調(diào)試語音模塊,藍(lán)牙模塊,聲源定位留的,后面有6路開關(guān)分別就是選擇這3對(duì)功能了。
3.MPU6050電路下的語音+聲源定位轉(zhuǎn)接由6P的XH2.54的接口接到擴(kuò)展板上。
4.然后就是藍(lán)牙模塊電路,WS2812,避障及警示電路三種電路都有共同PMOS+NMOS結(jié)構(gòu),PMOS通常用于上管控制,當(dāng)時(shí)想的就是想要在運(yùn)行其中一種模式時(shí),其它的模式通過MOS管直接斷電實(shí)現(xiàn)0功耗,每個(gè)MOS管都并聯(lián)了個(gè)小開關(guān)也是調(diào)試用;
CW32的每個(gè)IO引腳內(nèi)部結(jié)構(gòu)都由保護(hù)電路,由上下兩個(gè)同方向的二極管鉗位外部的電壓不得大于3.7V左右,不得小于-0.3V左右;
所以想控制5V輸入給電路,就是用了這種結(jié)構(gòu),每個(gè)電路都使用了單獨(dú)的5V轉(zhuǎn)3.3V保證各個(gè)電路的3.3V不會(huì)互相打擾。
Ⅳ、程序聯(lián)調(diào)
1.確定一個(gè)思路將所有功能組織在一個(gè)大循環(huán)里就行:由于之前我們設(shè)置好了MPU6050的寄存器,每10ms會(huì)進(jìn)一次中斷,我們借此使整個(gè)大循環(huán)10MS執(zhí)行一次,實(shí)現(xiàn)這種操作只需要:

設(shè)立一個(gè)觸發(fā)標(biāo)志位,在大循環(huán)中判斷標(biāo)志位執(zhí)行程序即可,由于標(biāo)志位是每10ms會(huì)被置位,主循環(huán)執(zhí)行一遍又是小于10ms的,所以主循環(huán)每一個(gè)10ms都會(huì)被執(zhí)行一次。
對(duì)應(yīng)的main函數(shù)里

這么執(zhí)行就行。
2.先由三個(gè)串口接收函數(shù)來確定小車此時(shí)的模式,由于使用接收標(biāo)志位來判斷是否有新數(shù)據(jù)所以標(biāo)志位就不會(huì)被隨意誤刷新:

3.通過語音模塊的接收數(shù)據(jù)來確定此時(shí)模式,并且在另一種模式?jīng)]有來之前,是不會(huì)被改變的。

4.藍(lán)牙模式:

5.跟隨模式:先對(duì)接收到的5次聲源數(shù)據(jù)進(jìn)行采集,并進(jìn)行排序?yàn)V波,以此確認(rèn)真正的聲源方向,然后根據(jù)聲源偏離方向的不同,給左右兩個(gè)輪子的前進(jìn)力度都不同:

6.避障模式:可以通過代碼看出在測出距離后根據(jù)距離的不同控制不一樣的速度:

7.語音模式:融合一些時(shí)間和速度達(dá)到轉(zhuǎn)到相應(yīng)的角度,代碼看一下就知道了,j每加1就相當(dāng)于以當(dāng)前的力度執(zhí)行了10ms,于是以相同力度執(zhí)行不同時(shí)間就可以造成轉(zhuǎn)至不同角度了:

Ⅴ、完善機(jī)械結(jié)構(gòu)
重新拆開優(yōu)化結(jié)構(gòu)使兩輪子軸心一致,高度盡可能小降低重心,定制個(gè)亞克力外殼,將外露的導(dǎo)線理順更加的美觀。

Ⅵ、調(diào)整參數(shù)與PID
1.調(diào)PID:
四個(gè)參數(shù):

(1)全部歸零
(2)直立環(huán)慢慢增大Kp直至小車低頻高幅震蕩
(3)直立環(huán)慢慢增大Kd直至小車高頻低幅震蕩
(4)統(tǒng)一乘以0.6-0.8作為最終參數(shù)
(5)速度環(huán)Kp與Ki之間的大小關(guān)系是200倍,Kp可以從0.1慢慢加0.1看看效果,若加速倒下將兩系數(shù)都加上負(fù)號(hào)即可,直至理想效果。
2.調(diào)速度等參數(shù):
調(diào)整上面所說的,如藍(lán)牙模式下的前進(jìn)后退速度,語音模式下的轉(zhuǎn)彎力度,避障模式下的變速程度等等。
-
智能車
+關(guān)注
關(guān)注
21文章
413瀏覽量
78586 -
平衡車
+關(guān)注
關(guān)注
7文章
82瀏覽量
28344 -
CW32
+關(guān)注
關(guān)注
1文章
326瀏覽量
1967
發(fā)布評(píng)論請(qǐng)先 登錄
CW32多玩法平衡車——基于傳統(tǒng)的平衡車之上擴(kuò)展而來
請(qǐng)問CW32 UART用于數(shù)據(jù)收發(fā)的具體過程是怎樣的?
CW32單片機(jī)如何讓生活更便捷
CW32時(shí)鐘運(yùn)行中失效檢測的流程是什么?CW32時(shí)鐘運(yùn)行中失效檢測注意事項(xiàng)有哪些呢?
CW32 MCU在高頻率運(yùn)行下的系統(tǒng)穩(wěn)定性的提升方案
基于芯源CW32 MCU的LED閃爍示例及代碼分析
如何在CW32 MCU上優(yōu)化I2C通信
使用J-Flash來編程CW32 MCU
CW32 MCU用什么IDE開發(fā)?
CW32 MCU有哪些系列?
打開FSP配置器界面的具體步驟
CW32多玩法平衡車——具體步驟及其內(nèi)容
評(píng)論