- 基于ARM Cortex-M3的STM32系列嵌入式微控制器應(yīng)用實(shí)踐
- 彭剛 秦志強(qiáng)編著
- 1367字
- 2018-12-27 16:01:52
3.2 STM32單片機(jī)程序模塊化設(shè)計(jì)
圖3.13定義了機(jī)器人的前后左右四個(gè)方向。在第2章實(shí)際上你應(yīng)該已經(jīng)發(fā)現(xiàn),如果按照圖3.13前進(jìn)方向的定義,機(jī)器人向前走時(shí),從機(jī)器人的左邊看,它向前走時(shí)輪子是逆時(shí)針旋轉(zhuǎn)的;從右邊看另一個(gè)輪子則是順時(shí)針旋轉(zhuǎn)的。

圖3.13 機(jī)器人及其前進(jìn)方向的定義
任務(wù)二 基本巡航動作
發(fā)給單片機(jī)控制引腳的高電平持續(xù)時(shí)間決定了伺服舵機(jī)旋轉(zhuǎn)的速度和方向。for循環(huán)的參數(shù)控制了發(fā)送給電機(jī)的脈沖數(shù)量。由于每個(gè)脈沖的時(shí)間是相同的,因而for循環(huán)的參數(shù)也控制了伺服電機(jī)運(yùn)行的時(shí)間。下面是使機(jī)器人向前走三秒鐘的程序?qū)嵗?/p>
例程:RobotForwardThreeSeconds.c
● 確保控制器和伺服電機(jī)都已接通電源;
● 輸入、保存、編譯、下載并運(yùn)行程序RobotForwardThreeSeconds.c。
#include "stm32f10x_heads.h"
#include "HelloRobot.h"
int main(void)
{
int counter;
BSP_Init();
USART_Configuration();
printf("Program Running!\n");
for(counter=0;counter<130;counter++)//運(yùn)行3秒
{
GPIO_SetBits(GPIOD, GPIO_Pin_10);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD, GPIO_Pin_9);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
while(1);
}
RobotForwardThreeSeconds.c是如何工作的?
理解該例程的運(yùn)行你應(yīng)該沒什么問題:for循環(huán)體中前三行語句使左側(cè)電機(jī)逆時(shí)針旋轉(zhuǎn),接著的三行語句使右側(cè)電機(jī)順時(shí)針旋轉(zhuǎn)。因此兩個(gè)輪子轉(zhuǎn)向機(jī)器人的前端,使機(jī)器人向前運(yùn)動。整個(gè)for循環(huán)執(zhí)行130次大約需要3秒鐘,從而機(jī)器人也向前運(yùn)動3秒鐘。
關(guān)于例程的一點(diǎn)說明
例程中使用printf函數(shù)是為了起提示作用。若你覺得串口線影響了機(jī)器人的運(yùn)動,可以不用此函數(shù);還有一個(gè)進(jìn)行調(diào)試的方法:讓機(jī)器人的前端懸空,讓伺服電機(jī)空轉(zhuǎn)。這樣調(diào)試起來就方便了,機(jī)器人不會到處亂跑。后面的例程調(diào)試也是這樣。
該你了——調(diào)節(jié)距離和速度
delay_nus函數(shù)的參數(shù)n為1700和1300都使電機(jī)接近它們的最大速度旋轉(zhuǎn)。把每個(gè)delay_nus函數(shù)的參數(shù)n設(shè)定得更接近讓電機(jī)保持停止的值——1500,可以使機(jī)器人減速。
向后走,原地轉(zhuǎn)彎和繞軸旋轉(zhuǎn)
將delay_nus函數(shù)的參數(shù)n以不同的值組合就可以使機(jī)器人以其他的方式運(yùn)行,你可以在一個(gè)程序中實(shí)現(xiàn)機(jī)器人向前走、左轉(zhuǎn)、右轉(zhuǎn)及向后走。
例程:ForwardLeftRightBackward.c
● 輸入、保存并運(yùn)行程序ForwardLeftRightBackward.c。
#include "stm32f10x_heads.h" #include "HelloRobot.h" int main(void) { int counter; BSP_Init(); USART_Configuration(); printf("Program Running!\n"); for(counter=1;counter<=65;counter++)//向前 { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } for(counter=1;counter<=26;counter++)//向左轉(zhuǎn) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } for(counter=1;counter<=26;counter++)//向右轉(zhuǎn) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } for(counter=1;counter<=65;counter++)//向后 { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } while(1); }
該你了——以一個(gè)輪子為支點(diǎn)旋轉(zhuǎn)
你可以使機(jī)器人繞一個(gè)輪子旋轉(zhuǎn)。訣竅是使一個(gè)輪子不動而另一個(gè)旋轉(zhuǎn)。例如,保持左輪不動而右輪從前面順時(shí)針旋轉(zhuǎn),機(jī)器人將以左輪為軸旋轉(zhuǎn)。
GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1500); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20);
如果你想使它從前面向右旋轉(zhuǎn),很簡單,停止右輪,左輪從前面逆時(shí)針旋轉(zhuǎn)。
GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1500); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20);
用剛討論過的代碼片段替代前進(jìn)、左轉(zhuǎn)、右轉(zhuǎn)和后退相應(yīng)的代碼片段,通過更改每個(gè)for循環(huán)的循環(huán)次數(shù)來調(diào)整每個(gè)動作的運(yùn)行時(shí)間,更改注釋來反應(yīng)每個(gè)新的旋轉(zhuǎn)動作。
運(yùn)行更改后的程序,驗(yàn)證上述旋轉(zhuǎn)運(yùn)動是否不同。
任務(wù)三 勻加速/減速運(yùn)動
在前面機(jī)器人運(yùn)動過程中,你是否發(fā)現(xiàn)機(jī)器人在每次啟動和停止的時(shí)候,是不是有些太快,從而導(dǎo)致機(jī)器人幾乎要傾倒。為什么會這樣呢?回憶一下你學(xué)過的物理知識,還記得牛頓第二定律和運(yùn)動學(xué)知識嗎?前面的程序總是直接就給機(jī)器人伺服電機(jī)輸出最大速度控制命令。根據(jù)運(yùn)動學(xué)知識,一個(gè)物體要從零加速到最大運(yùn)動速度時(shí),時(shí)間越短,所需加速度就越大。而根據(jù)牛頓定律,加速度越大,物體所受的慣性力就越大。因此,前面的程序因?yàn)闆]有給機(jī)器人足夠的加速時(shí)間,所以受到的慣性力就比較大,從而導(dǎo)致機(jī)器人在啟動和停止有一個(gè)較大的前傾力或者后坐力。要消除這種情況,就必須讓機(jī)器人速度漸漸增加或漸漸減小。采用均勻加速/減速是一種比較好的速度控制策略,這樣不僅可以讓機(jī)器人運(yùn)動得更加平穩(wěn),還可以增加機(jī)器人電機(jī)的使用壽命。
編寫勻加速運(yùn)動程序
勻加速運(yùn)動程序片段示例:
for(pulseCount=10;pulseCount<=200;pulseCount=pulseCount+10) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1500+pulseCount); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1500-pulseCount); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); }
上述for循環(huán)語句能使機(jī)器人的速度由停止到全速。循環(huán)每重復(fù)執(zhí)行一次,變量pulseCount就增加10:第一次循環(huán)時(shí),變量pulseCount的值是10,此時(shí)發(fā)給PD10、PD9的脈沖的寬度分別為1.51ms、1.49ms;第二次循環(huán)時(shí),變量pulseCount的值是20,此時(shí)發(fā)給PD10、PD9的脈沖的寬度分別為1.52ms、1.48ms。隨著變量pulseCount值的增加,電機(jī)的速度也在逐漸增加。到執(zhí)行第20次循環(huán)時(shí),變量pulseCount的值是200,此時(shí)發(fā)給PD10、PD9的脈沖的寬度分別為1.7ms、1.3ms,電機(jī)全速運(yùn)轉(zhuǎn)。
回顧第2章任務(wù)三,for循環(huán)也可以由高向低計(jì)數(shù)。你可以通過使用for(pulseCount=200;pulseCount>=0; pulseCount=pulseCount-10)來實(shí)現(xiàn)速度的逐漸減小。下面是一個(gè)使用for循環(huán)來實(shí)現(xiàn)電機(jī)速度逐漸增加到全速然后逐步減小的例子。
例程:StartAndStopWithRamping.c
#include "stm32f10x_heads.h" #include "HelloRobot.h" int main(void) { int pulseCount; BSP_Init(); USART_Configuration(); printf("Program Running!\n"); for(pulseCount=10;pulseCount<=200;pulseCount=pulseCount+10) { GPIO_SetBits(GPIOD,GPIO_Pin_10); delay_nus(1500+pulseCount); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD,GPIO_Pin_9); delay_nus(1500-pulseCount); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } for(pulseCount=1;pulseCount<=75;pulseCount++) { GPIO_SetBits(GPIOD,GPIO_Pin_10); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD,GPIO_Pin_9); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } for(pulseCount=200;pulseCount>=0;pulseCount=pulseCount-10) { GPIO_SetBits(GPIOD,GPIO_Pin_10); delay_nus(1500+pulseCount); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD,GPIO_Pin_9); delay_nus(1500-pulseCount); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } while(1); }
● 輸入、保存并運(yùn)行程序StartAndStopWithRamping.c;
● 驗(yàn)證機(jī)器人是否逐漸加速到全速,保持一段時(shí)間,然后逐漸減速到停止。
任務(wù)四 用函數(shù)調(diào)用簡化運(yùn)動程序
在第4章,你的機(jī)器人將需要執(zhí)行各種運(yùn)動來避開障礙物和完成其他動作。不過,無論機(jī)器人要執(zhí)行何種動作,都離不開前面討論的各種基本動作。為了各種應(yīng)用程序方便使用這些基本動作程序,你可以將這些基本動作放在函數(shù)中,供其他函數(shù)調(diào)用來簡化程序。
C語言提供了強(qiáng)大的函數(shù)定義功能。一個(gè)C程序就是由一個(gè)主函數(shù)和若干個(gè)其他函數(shù)構(gòu)成,由主函數(shù)調(diào)用其他函數(shù),其他函數(shù)也可以相互調(diào)用。同一個(gè)函數(shù)可以被一個(gè)或多個(gè)函數(shù)調(diào)用任意多次。實(shí)際上,為了實(shí)現(xiàn)復(fù)雜的程序設(shè)計(jì),在所有的計(jì)算機(jī)高級語言中都有子程序或者子過程的概念。在C語言程序中,子程序的作用就是由函數(shù)來完成的。從函數(shù)定義的角度來看,函數(shù)有兩種:
(1)標(biāo)準(zhǔn)函數(shù),即庫函數(shù)。由開發(fā)系統(tǒng)提供。用戶不必自己定義而直接使用,只需在程序前包含有該函數(shù)原型的頭文件即可在程序中直接調(diào)用,如前面已經(jīng)用到的串口標(biāo)準(zhǔn)輸出函數(shù)(printf)。應(yīng)該說明,不同的語言編譯系統(tǒng)提供的庫函數(shù)的數(shù)量和功能會有一些不同,但許多基本函數(shù)是共同的。
(2)用戶定義函數(shù),以解決你的專門需要。不僅要在程序中定義函數(shù)本身,而且在主調(diào)函數(shù)模塊中還必須對該被調(diào)函數(shù)進(jìn)行類型說明,然后才能使用。
main函數(shù)的返回值
前面說過,main函數(shù)是不能被其他函數(shù)調(diào)用的,那它的返回值類型int是怎么回事呢?
其實(shí)不難理解,main函數(shù)執(zhí)行完之后,它的返回值是給操作系統(tǒng)的。雖然在main函數(shù)體內(nèi)并沒有什么語句來指出返回值的大小,但系統(tǒng)默認(rèn)的處理方式是:當(dāng)main函數(shù)成功執(zhí)行,它的返回值為1;否則為0。
現(xiàn)在看看下面的函數(shù)定義:
void Forward(void)
{
int i;
for(i=1;i<=65;i++)
{
GPIO_SetBits(GPIOD, GPIO_Pin_10);
delay_nus(1700);
GPIO_ResetBits(GPIOD,GPIO_Pin_10);
GPIO_SetBits(GPIOD, GPIO_Pin_9);
delay_nus(1300);
GPIO_ResetBits(GPIOD,GPIO_Pin_9);
delay_nms(20);
}
}
Forward函數(shù)可以使機(jī)器人向前運(yùn)動約1.5s,該函數(shù)沒有形參,也沒有返回值。在主程序中,你可以調(diào)用它來讓你的機(jī)器人向前運(yùn)動約1.5s。但是這個(gè)函數(shù)并沒有太大的使用價(jià)值,如果你想讓你的機(jī)器人向前運(yùn)動2s,該怎么辦呢?是重新寫一個(gè)函數(shù)來實(shí)現(xiàn)這個(gè)運(yùn)動嗎?當(dāng)然不是!通過修改上面的函數(shù),給它增加兩個(gè)形式參數(shù),一個(gè)是脈沖數(shù)量,另一個(gè)是速度參數(shù),這樣主程序調(diào)用時(shí)就可以按照你的要求靈活設(shè)置這些參數(shù),從而使函數(shù)真正成為一個(gè)有用的模塊。重新定義向前運(yùn)動函數(shù)如下:
void Forward(int PulseCount,int Velocity) //Velocity should be between 0 and 200 { int i; for(i=1;i<=PulseCount;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1500+Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1500-Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } }
函數(shù)定義旁有一行注釋,提醒你在調(diào)用該函數(shù)時(shí),速度參量的值必須在0~200之間。
注釋符
除“//”外,C語言還提供了另一種語句注釋符——“/*”和“ */”。
“/*”和“*/”必須成對使用,在它們之間的內(nèi)容將被注釋掉。它的作用范圍比“//”大:“//”僅僅對它所在的一行起注釋作用;但“/*…*/”可以對多行注釋。
注釋是你在學(xué)習(xí)程序設(shè)計(jì)時(shí)要養(yǎng)成的良好習(xí)慣。
下面是一個(gè)完整的使用向前、左轉(zhuǎn)、右轉(zhuǎn)和向后四個(gè)函數(shù)的例程。
例程:MovementsWithFunctions.c
● 輸入、保存、編譯、下載并運(yùn)行程序MovementsWithFunctions.c。
#include "stm32f10x_heads.h" #include "HelloRobot.h" void Forward(int PulseCount,int Velocity) // Velocity should be between 0 and 200 { int i; for(i=1;i<= PulseCount;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1500+ Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1500- Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } void Left(int PulseCount,int Velocity) { int i; for(i=1;i<= PulseCount;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1500-Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1500-Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } void Right(int PulseCount,int Velocity) { int i; for(i=1;i<= PulseCount;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1500+Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1500+Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } void Backward(int PulseCount,int Velocity) { int i; for(i=1;i<= PulseCount;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1500-Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1500+ Velocity); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } int main(void) { BSP_Init(); USART_Configuration(); printf("Program Running!\n"); Forward(65,200); Left(26,200); Right(26,200); Backward(65,200); while(1); }
這個(gè)程序的運(yùn)行結(jié)果與程序ForwardLeftRightBackward.c產(chǎn)生的效果是相同的。你有沒有發(fā)現(xiàn)四個(gè)函數(shù)的具體實(shí)現(xiàn)是不是有些啰嗦。四個(gè)函數(shù)的具體實(shí)現(xiàn)部分幾乎完全一樣,有沒有可能將這些函數(shù)進(jìn)一步歸納,用一個(gè)函數(shù)來實(shí)現(xiàn)所有這些功能呢?當(dāng)然有,前面的四個(gè)函數(shù)都用了兩個(gè)形式參數(shù),一個(gè)是控制時(shí)間的脈沖個(gè)數(shù),另一個(gè)是控制運(yùn)動速度的參數(shù),而四個(gè)函數(shù)實(shí)際上代表了四個(gè)不同的運(yùn)動方向。如果能夠通過參數(shù)控制運(yùn)動方向,顯然這四個(gè)函數(shù)就完全可以簡化成為一個(gè)更為通用的函數(shù),它不僅可以涵蓋以上四個(gè)基本運(yùn)動,同時(shí)還可以使機(jī)器人朝你希望的方向運(yùn)動。
由于機(jī)器人由兩個(gè)輪子驅(qū)動,實(shí)際上兩個(gè)輪子的不同速度組合控制著機(jī)器人的運(yùn)動速度和方向,因此可以直接用兩個(gè)車輪的速度作為形式參數(shù),就可以將所有的機(jī)器人運(yùn)動用一個(gè)函數(shù)來實(shí)現(xiàn)。
例程:MovementsWithOneFuntion.c
這個(gè)例子使你的機(jī)器人做同樣動作,但是它只用了一個(gè)子函數(shù)來實(shí)現(xiàn)。
#include "stm32f10x_heads.h" #include "HelloRobot.h" void Move(int counter,int PC1_pulseWide,int PC0_pulseWide) { int i; for(i=1;i<=counter;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(PC1_pulseWide); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(PC0_pulseWide); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } int main(void) { BSP_Init(); USART_Configuration(); printf("Program Running!\n"); Move(65,1700,1300); Move(26,1300,1300); Move(26,1700,1700); Move(65,1300,1700); while(1); }
● 輸入、保存并運(yùn)行程序MovementsWithOneFuntion.c;
● 你的機(jī)器人是否執(zhí)行了你熟悉的前、左、右、后運(yùn)動呢?
任務(wù)五 高級主題——用數(shù)組建立復(fù)雜運(yùn)動
到目前為止你已經(jīng)試過三種不同的編程方法來使機(jī)器人向前走,左轉(zhuǎn),右轉(zhuǎn)和向后走。每種方法都有它的優(yōu)點(diǎn),但是如果你要讓機(jī)器人執(zhí)行一個(gè)更長,更復(fù)雜的動作時(shí)用這些方法都很麻煩。下面要介紹的兩個(gè)例子將用子函數(shù)來實(shí)現(xiàn)每個(gè)簡單的動作,將復(fù)雜的運(yùn)動存儲在數(shù)組中,然后在程序執(zhí)行過程中讀出并解碼。避免了重復(fù)調(diào)用一長串子函數(shù)。這里,你要用到C語言的數(shù)據(jù)類型——數(shù)組。
在程序設(shè)計(jì)中,為了處理方便,可以把具有相同類型的若干變量按有序的形式組織起來。這些按序排列的同類數(shù)據(jù)元素的集合稱為數(shù)組。一個(gè)數(shù)組可以分解為多個(gè)數(shù)組元素,根據(jù)數(shù)組元素?cái)?shù)據(jù)類型的不同,數(shù)組可以分為多種不同類型。數(shù)組又分為一維數(shù)組、二維數(shù)組甚至三維數(shù)組。本節(jié)只會用到一維數(shù)組。例如,下面的語句定義了一個(gè)字符型數(shù)組,該數(shù)組有10個(gè)元素,并對這10個(gè)元素進(jìn)行了初始化。
char Navigation[10]={'F','L','F','F','R','B','L','B','B','Q'};
字符串和字符串結(jié)束標(biāo)志
在C語言中沒有專門的字符串變量,通常用一個(gè)字符數(shù)組或字符指針來存放一個(gè)字符串。字符串常量在存儲時(shí),系統(tǒng)自動在字符串的末尾加一個(gè)“串結(jié)束標(biāo)志”,即ASCII碼值為0的字符NULL,常用“\0”表示。因此在程序中,長度為n字符的字符串常量在內(nèi)存中占有n+1個(gè)字節(jié)的存儲空間。C語言允許用字符串的方式對數(shù)組作初始化賦值,如Navigation[10]的初始化賦值可寫為:
char Navigation[10]={“FLFFRBLBBQ”};
或者去掉“{}”,寫為:char Navigation[10]=“FLFFRBLBBQ”;
要特別注意字符與字符串的區(qū)別,除了表示形式不同外,其存儲性質(zhì)也不相同,字符“A”只占1字節(jié),而字符串“A”占2字節(jié)。
下面的例程采用字符數(shù)組定義一系列復(fù)雜的運(yùn)動。
例程:NavigationWithSwitch.c
● 輸入、保存、編譯、下載并運(yùn)行程序NavigationWithSwitch.c。
#include "stm32f10x_heads.h" #include "HelloRobot.h" void Forward(void) { int i; for(i=1;i<=65;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } void Left_Turn(void) { int i; for(i=1;i<=26;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } void Right_Turn(void) { int i; for(i=1;i<=26;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } void Backward(void) { int i; for(i=1;i<=65;i++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(1300); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(1700); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } } int main(void) { char Navigation[10]={'F','L','F','F','R','B','L','B','B','Q'}; int address=0; BSP_Init(); USART_Configuration(); printf(" Program Running!\n"); while(Navigation[address]!='Q') { switch(Navigation[address]) { case 'F':Forward();break; case 'L':Left_Turn();break; case 'R':Right_Turn();break; case 'B':Backward();break; } address++; } while(1); }
你的機(jī)器人是否走了一個(gè)矩形?如果它走得更像一個(gè)梯形,你可能需要調(diào)節(jié)轉(zhuǎn)動程序中for循環(huán)的循環(huán)次數(shù),使其旋轉(zhuǎn)精確的90度。
在程序主函數(shù)中定義了一個(gè)字符數(shù)組,這個(gè)數(shù)組中存儲的是一些命令:F表示向前運(yùn)動,L表示向左轉(zhuǎn),R表示向右轉(zhuǎn),B表示向后退,Q表示程序結(jié)束。之后,定義了一個(gè)int型變量address,用來作為訪問數(shù)組的索引。接著是一個(gè)while循環(huán),注意到這個(gè)循環(huán)的條件表達(dá)式與前面的不同:只有當(dāng)前訪問的數(shù)組值不為Q時(shí),才執(zhí)行循環(huán)體內(nèi)的語句。在循環(huán)內(nèi),每次執(zhí)行switch語句后,都要更新address,以使下次循環(huán)時(shí)執(zhí)行新的運(yùn)動。
當(dāng)Navigation[address]為“F”時(shí),執(zhí)行向前運(yùn)動的函數(shù)Forward();當(dāng)Navigation[address]為“L”時(shí),執(zhí)行向左轉(zhuǎn)的函數(shù)Left_Turn();當(dāng)Navigation[address]為“R”時(shí),執(zhí)行向右轉(zhuǎn)的函數(shù)Right_Turn();當(dāng)Navigation[address]為“B”時(shí),執(zhí)行向后運(yùn)動的函數(shù)Backward()。你可以增加或刪除數(shù)組中的字符來獲取新的運(yùn)動路線。記住:數(shù)組中的最后字符應(yīng)該是“Q”。
例程:NavigationWithValues.c
在本例程中,將不使用子函數(shù),而是使用三個(gè)整型數(shù)組來存儲控制機(jī)器人運(yùn)動的三個(gè)變量,即循環(huán)的次數(shù)和控制左右電機(jī)運(yùn)動的兩個(gè)參數(shù)。具體定義如下:
int Pulses_Count[5]={65,26,26,65,0};
int Pulses_Left[4]={1700,1300,1700,1300};
int Pulses_Right[4]={1300,1300,1700,1700};
int型變量address作為訪問數(shù)組的索引值,每次用address提取一組數(shù)據(jù):Pulses_Count[address],Pulses_Left[address],Pulses_Right[address],這些變量值被放在下面的代碼塊中,作為機(jī)器人運(yùn)動一次的參數(shù)。
for(int counter=1;counter<=Pulses_Count[address];counter++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(Pulses_Left[address]); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(Pulses_Right[address]); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); }
address加1,再提取一組數(shù)據(jù),作為機(jī)器人下次運(yùn)動的參數(shù)。以此繼續(xù)直至Pulses_Count[address]=0時(shí),機(jī)器人停止運(yùn)動。具體程序如下:
#include "stm32f10x_heads.h" #include "HelloRobot.h" int main(void) { int Pulses_Count[5]={65,26,26,65,0}; int Pulses_Left[4]={1700,1300,1700,1300}; int Pulses_Right[4]={1300,1300,1700,1700}; int address=0; int counter; BSP_Init(); USART_Configuration(); printf("Program Running!\n"); while(Pulses_Count[address]!=0) { for(counter=1;counter<=Pulses_Count[address];counter++) { GPIO_SetBits(GPIOD, GPIO_Pin_10); delay_nus(Pulses_Left[address]); GPIO_ResetBits(GPIOD,GPIO_Pin_10); GPIO_SetBits(GPIOD, GPIO_Pin_9); delay_nus(Pulses_Right[address]); GPIO_ResetBits(GPIOD,GPIO_Pin_9); delay_nms(20); } address++; } while(1); }
- FPGA嵌入式項(xiàng)目開發(fā)三位一體實(shí)戰(zhàn)精講
- 基于HCS12的嵌入式系統(tǒng)設(shè)計(jì)
- 單片機(jī)應(yīng)用技術(shù)
- PIC單片機(jī)常用模塊與綜合系統(tǒng)設(shè)計(jì)實(shí)例精講
- AVR單片機(jī)實(shí)用程序設(shè)計(jì)
- 嵌入式系統(tǒng)Linux內(nèi)核開發(fā)實(shí)戰(zhàn)指南(ARM平臺)
- 單片機(jī)原理與應(yīng)用技術(shù)
- STM32W無線射頻Zigbee單片機(jī)原理與應(yīng)用
- 計(jì)算機(jī)與嵌入式系統(tǒng)架構(gòu)
- AVR單片機(jī)原理與應(yīng)用實(shí)例
- 深度學(xué)習(xí)實(shí)踐教程
- Protel DXP 2004應(yīng)用100例
- 基于Quartus II的FPGA/CPLD設(shè)計(jì)實(shí)例精解
- AVR單片機(jī)與傳感器基礎(chǔ)
- 單片機(jī)與物聯(lián)網(wǎng)技術(shù)應(yīng)用實(shí)戰(zhàn)教程