官术网_书友最值得收藏!

2.4 STM32單片機I/O端口的應用

任務五 機器人伺服電機控制信號

控制伺服電機轉動速度的脈沖信號如圖2.10、圖2.11和圖2.12所示。

圖2.10 電機轉速為零的控制信號時序圖

圖2.11 1.3ms的控制脈沖序列使電機順時針全速旋轉

圖2.12 1.7ms的連續脈沖序列使電機逆時針全速旋轉

圖2.10所示是高電平持續1.5ms低電平持續20ms,然后不斷重復地控制脈沖序列。該脈沖序列發給經過零點標定后的伺服電機,伺服電機不會旋轉。如果此時你的電機旋轉,表明電機需要標定。此時,你可調節伺服電機的可調電阻使電機停止旋轉??刂齐姍C運動轉速的是高電平持續的時間,當高電平持續時間為1.3ms時,電機順時針全速旋轉,當高電平持續時間1.7ms時,電機逆時針速旋轉。下面你將看到如何給STM32單片機微控制器編程使PD端口的第10腳(PD10)來發出伺服電機的控制信號。

在進行下面的實驗之前,你必須首先確認一下機器人兩個伺服電機的控制線是否已經正確地連接到了STM32單片機教學開發板的兩個專用電機控制接口上。按照圖2.13所示的電機連接原理圖和實際接線圖進行檢查?!昂诰€”表示地線,“紅線”表示電源線,“白線”表示信號線。PD9用來控制左邊的伺服電機,而PD10引腳則用來控制右邊的伺服電機。

圖2.13 伺服電機與教學開發板的連接原理圖(左)和實際接線圖(右)

顯然這里對微控制器編程發給伺服電機的高、低電平信號必須具備更精確的時間。因為單片機只有整數,沒有小數,所以要生成伺服電機的控制信號,要求具有比delay_nms()函數的時間更精確的函數,這就需要用另一個延時函數delay_nus()。前面已經介紹過,這個函數可以實現更小的延時,它的延時單位是微秒,即千分之一毫秒,參數n為延時微秒數。

看看下面的代碼片斷:

      while (1)
      {
          GPIO_SetBits(GPIOD,GPIO_Pin_10);   //PD10輸出高電平
          delay_nus(1500);                   //延時1500μs
          GPIO_ResetBits(GPIOD,GPIO_Pin_10); //PD10輸出低電平
          delay_nus(20000);                  //延時20ms
      }

如果用這個代碼段代替例程Led_Blink.c中相應程序片斷,它是不是就會輸出圖2.6所示的脈沖信號?肯定是!如果你手邊有個示波器,可以用示波器觀察PD10腳輸出的波形是不是如圖2.6所示。此時,連接到該腳的機器人輪子是不是靜止不動。如果它在慢慢轉動,就說明你的機器人伺服電機可能沒有經過調整。

同樣,用下面的程序片斷代替例程Led_Blink.c中相應程序片斷,編譯、連接下載執行代碼,觀察連接到PD10腳的機器人輪子是不是順時針全速旋轉。

      while(1)
      {
          GPIO_SetBits(GPIOD,GPIO_Pin_10);   //PD10輸出高電平
          delay_nus(1300);                   //延時1500μs
          GPIO_ResetBits(GPIOD,GPIO_Pin_10); //PD10輸出低電平
          delay_nus(20000);                  //延時20ms
      }

用下面的程序片斷代替例程Led_Blink.c中相應程序片斷,編譯、連接下載執行代碼,觀察連接到PD10腳的機器人輪子是不是逆時針全速旋轉。

      while (1)
      {
          GPIO_SetBits(GPIOD,GPIO_Pin_10);   //PD10輸出高電平
          delay_nus(1700);                   //延時1500μs
          GPIO_ResetBits(GPIOD,GPIO_Pin_10); //PD10輸出低電平
          delay_nus(20000);                  //延時20ms
      }

該你了——讓機器人的兩個輪子全速旋轉

剛才是讓連接到PD10腳的伺服電機輪子全速旋轉,下面你自己可以修改程序讓連接到PD9機器人輪子全速旋轉。

當然,最后你需要修改程序,讓機器人的兩個輪子都能夠旋轉。讓機器人兩個輪子都順時鐘全速旋轉的程序參考下面的程序。

例程:BothServo.c

● 接通板上的電源,輸入、保存、下載并運行程序(整個過程請參考第1章);

● 觀察機器人小車的運動行為。

      #include "stm32f10x_heads.h"
      #include "HelloRobot.h"
      int main(void)
      {
        BSP_Init();
        USART_Configuration();
        printf("Program Running!\n");
        while (1)
        {
          GPIO_SetBits(GPIOD, GPIO_Pin_10);
          GPIO_SetBits(GPIOD, GPIO_Pin_9);
          delay_nus(1300);
          GPIO_ResetBits(GPIOD,GPIO_Pin_10);
          GPIO_ResetBits(GPIOD,GPIO_Pin_9);
          delay_nms(20);
        }
      }

注意:上述程序用到了兩個不同的延時函數,效果與前面例子一樣。運行上述程序時,你是不是對機器人的運動行為感到驚訝!

任務六 計數并控制循環次數

任務五中已經通過對STM32單片機編程實現了對機器人伺服電機的控制,為了讓微控制器不斷發出控制指令,你用到了以while(1)開頭的死循環(即永不結束的循環)。不過在實際的機器人控制過程中,你會經常要求機器人運動一段給定的距離或者一段固定的時間。這時就需要你能控制代碼執行的次數。

最方便的控制一段代碼執行次數的方法是利用for循環,語法如下:

      for(表達式1;表達式2;表達式3) 語句

例如,下面是一個用整型變量myCounter來計數的for循環程序片斷。每執行一次循環,它會顯示myCounter的值。

      for(myCounter=1; myCounter<=10; myCounter++)
      {
      printf(“%d”,myCounter);
      delay_nms(500);
      }

該你了——不同的初始值和終值及計數步長

你可以修改表達式3來使myCounter以不同步長計數,而不是按9,10,11,…來計,你可以讓它每次增加2(9,11,13,…)或增加5(10,15,20,…)或任何你想要的步進,遞增或遞減都可以。下面的例子是每次減3。

      for(myCounter=21; myCounter>=9; myCounter=myCounter-3)
      {
      printf(“%d\n”,myCounter);
      delay_nms(500);
      }

for循環控制電機的運行時間

到目前為止,你已經理解了利用脈沖寬度調制(Pulse Width Modulation,PWM)來控制電機旋轉速度和方向的原理。控制電機速度和方向的方法是非常簡單的??刂齐姍C運行的時間也非常簡單,那就是用for循環。下面是for循環的例子,它會使電機運行幾秒鐘。

      for(Counter=1;Counter<=100;i++)
      {
        GPIO_SetBits(GPIOD, GPIO_Pin_10);
        delay_nus(1700);
        GPIO_ResetBits(GPIOD,GPIO_Pin_10);
        delay_nms(20);
      }

讓我們來計算一下這個代碼能使電機轉動的確切的時間長度。每通過循環一次,delay_nus(1700)持續1.7 ms,delay_nms(20)持續20ms,其他語句的執行時間很少,可忽略。那么for循環整體執行一次的時間是:1.7ms+20ms=21.7ms,本循環執行100次,即就是21.7ms乘以100,時間=100×21.7ms=100×0.0217s=2.17s。

例程:ControlServoRunTimes.c

● 輸入、保存并運行程序;

● 驗證是否與PD10連接的電機逆時針旋轉2.17s,然后與PD9連接的電機旋轉4.34s。

      int main(void)
      {
        int Counter;
        BSP_Init();
        USART_Configuration();
        printf("Program Running!\n");
        for(Counter=1;Counter<=100;Counter++)
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_10);
            delay_nus(1700);
          GPIO_ResetBits(GPIOD,GPIO_Pin_10);
          delay_nms(20);
        }
        for(Counter=1;Counter<=200;Counter++)
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_9);
          delay_nus(1700);
            GPIO_ResetBits(GPIOD,GPIO_Pin_9);
          delay_nms(20);
        }
        while(1);
      }

假如你想讓兩個電機同時運行,給與PD10連接的電機發出1.7ms的脈寬,給與PD9連接的電機發出1.3ms的脈寬,現在每通過循環一次要用的時間是:

1.7ms——與PD10連接的電機

1.3ms——與PD8連接的電機

20 ms——中斷持續時間

---------- ------------------------------

一共是23 ms

假如你想讓電機運行3s,計算如下:脈沖數量=3 / 0.023= 130

現在,你可以將for循環中作如下修改,程序如下:

      for(counter=1;counter<=130;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);
      }

例程:BothServosThreeSeconds.c

下面是一個使電機向一個方向旋轉3s,然后反向旋轉的例子。

● 輸入、保存并運行程序。

      int main(void)
      {
        int counter;
        BSP_Init();
        USART_Configuration();
        printf("Program Running!\n");
        for(counter=1;counter<=130;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<=130;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);
      }

驗證每個機器人是否沿一個方向運行3s然后反方向運行3s。你是否注意到當電機同時反向的時候,它們總是保持同步運行?這將有什么作用呢?

任務七 用你的計算機來控制機器人的運動

在工業自動化、測控等領域,經常需要你的單片機與計算機通信。一方面,單片機需要讀取周邊傳感器的信息,并把數據傳給計算機;另一方面,計算機需要解釋和分析傳感器數據,然后把分析結果或者決策發給單片機以執行某種操作。

在第1章中你已經知道STM32單片機可以通過串口向計算機發送信息,本章將使用串口和串口調試終端軟件,從計算機向單片機發送數據來控制機器人的運動。

在本任務中,你需要編程讓STM32單片機從調試窗口接收兩個數據:發給伺服舵機的脈沖個數和脈沖寬度(以微秒為單位)。

例程:ControlServoWithComputer.c

● 輸入、保存、下載并運行程序ControlServoWithComputer.c;

● 驗證是否機器人各個輪子的轉動是不是同你期望的運動一樣。

      #include "stm32f10x_heads.h"
      #include "HelloRobot.h"
      unsigned int USART_Scanf()
      {
        u16 index = 0;
        u16 recdata;
        u16 tmp[5]={0,0,0,0,0};
        while(1)
        {
          /* Wait until RXNE = 1 */
          while(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==RESET);
          tmp[index] = (USART_ReceiveData(USART1));
        if(tmp[index] == '#')
        {
          if(index!=0)   break;
          else        continue;
          }
        index++;
        }
        /* Calculate the Corresponding value */
        if(index==1)
        recdata = (tmp[0] -0x30);
        if(index==2)
        recdata = (tmp[1] -0x30) + ((tmp[0] -0x30) * 10);
        if(index==3)
        recdata = (tmp[2] -0x30) + ((tmp[1] -0x30) * 10)+ ((tmp[0] -0x30) * 100);
        if(index==4)
        recdata = (tmp[3] -0x30) + ((tmp[2] -0x30) * 10)+ ((tmp[1] -0x30) * 100)+ ((tmp[0] -0x30) *
1000);
        return recdata;
      }
      int main(void)
      {
        int Counter;
        unsigned int PulseNumber,PulseDuration;
        BSP_Init();
        USART_Configuration();
        printf("Program Running!\r\n");
        printf("Please input pulse number:\r\n");
        PulseNumber=USART_Scanf();
        printf("Input pulse number is %d\r\n",PulseNumber);
        printf("Please input pulse duration:\r\n");
        PulseDuration=USART_Scanf();
        printf("Input pulse duration is %d\r\n",PulseDuration);
        for(Counter=1;Counter<=PulseNumber;Counter++)
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_10);
            delay_nus(PulseDuration);
            GPIO_ResetBits(GPIOD,GPIO_Pin_10);
            delay_nms(20);
        }
        for(Counter=1;Counter<=PulseNumber;Counter++)
        {
            GPIO_SetBits(GPIOD, GPIO_Pin_9);
            delay_nus(PulseDuration);
            GPIO_ResetBits(GPIOD,GPIO_Pin_9);
            delay_nms(20);
        }
        while(1);
      }

ControlServoWithComputer.c是如何工作的?

在這個程序中,單片機不僅向串口傳送信息給你看,而且還通過串口從計算機讀取輸入的數據。串口接收數據函數USART_Scanf的工作機制將在后面的章節講解,其作用是從計算機接收數據,計算機向單片機發出的數據以#作為結束標記,就像使用充值卡給電話(手機)充值時,輸入完賬號和密碼按#表示結束,如圖2.14所示。

圖2.14 例程運行過程

注意break和continue的區別:break是結束整個循環體,而continue是結束本次循環。

(1)首先輸出“Program Running!”和“Please input pulse number:”;

(2)程序處于等待狀態,等待你從串口調試軟件輸入數據,數據以“#”作為結束標記;

(3)將輸入的數據給變量PulseNumber,再把這個數據回傳給計算機顯示;

(4)輸出“Please input pulse duration:”;

(5)又處于等待狀態,等待你從串口調試軟件再次輸入數據,數據以“#”作為結束標記;

(6)將輸入的數據給變量PulseDuration,再把這個數據回傳給計算機顯示;

(7)電機運轉。

主站蜘蛛池模板: 卢湾区| 花垣县| 文安县| 通江县| 大关县| 汕尾市| 耿马| 嫩江县| 巧家县| 永靖县| 邮箱| 子长县| 宿迁市| 河北省| 镇雄县| 布尔津县| 财经| 中卫市| 怀来县| 绿春县| 青海省| 将乐县| 如东县| 龙海市| 霞浦县| 临洮县| 宽城| 阿城市| 荣成市| 牙克石市| 黔西| 金阳县| 瑞安市| 滨海县| 孝感市| 昌图县| 恩平市| 三亚市| 当雄县| 义乌市| 无为县|