久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 815|回復: 0
打印 上一主題 下一主題
收起左側

stm32f103c8t6單片機和PCF9685控制16路舵機通過串口調試程序

[復制鏈接]
跳轉到指定樓層
樓主
ID:1139558 發表于 2024-12-12 18:13 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
  1. #include "stm32f10x.h"                  // Device header
  2. #include "MyI2C.h"
  3. #include "PCA9685_Reg.h"
  4. #include "math.h"
  5. #include "Delay.h"
  6. #include "Serial.h"
  7. #include "OLED.h"
  8. #include "string.h"
  9. #include "stdlib.h"

  10. uint8_t Channel_Flag = 0;

  11. /**
  12.   * 函    數:PCA9685寫寄存器
  13.   * 參    數:RegAddress 寄存器地址,范圍:參考PCA9685手冊的寄存器描述
  14.   * 參    數:Data 要寫入寄存器的數據,范圍:0x00~0xFF
  15.   * 返 回 值:無
  16.   */
  17. void PCA9685_WriteReg(uint8_t RegAddress, uint8_t Data)
  18. {
  19.         MyI2C_Start();                                                //I2C起始
  20.         MyI2C_SendByte(ADDRESS);                        //發送從機地址,讀寫位為0,表示即將寫入
  21.         MyI2C_ReceiveAck();                                        //接收應答
  22.         MyI2C_SendByte(RegAddress);                        //發送寄存器地址
  23.         MyI2C_ReceiveAck();                                        //接收應答
  24.         MyI2C_SendByte(Data);                                //發送要寫入寄存器的數據
  25.         MyI2C_ReceiveAck();                                        //接收應答
  26.         MyI2C_Stop();                                                //I2C終止
  27. }

  28. //void PCA9685_Write(u8 addr,u8 data)    //   addr 表示要寫入數據的寄存器地址,data 表示要寫入的數據
  29. //{
  30. //        IIC_Start();                         //   發送 I2C 起始信號,開始 I2C 通信。
  31. //       
  32. //        IIC_Send_Byte(PCA_Addr);             //   發送 PCA_Addr = 0x80 ,告訴設備我們要寫入數據
  33. //        IIC_NAck();                          //   發送不應答信號,表示主控器不需要從設備接收更多數據。
  34. //       
  35. //        IIC_Send_Byte(addr);                 //   發送要寫入數據的寄存器地址。
  36. //        IIC_NAck();                          //   發送不應答信號。
  37. //       
  38. //        IIC_Send_Byte(data);                 //   發送要寫入的數據。
  39. //        IIC_NAck();                          //   發送不應答信號。
  40. //       
  41. //        IIC_Stop();                          //   發送 I2C 停止信號,結束本次通信。
  42. //       
  43. //}

  44. /**
  45.   * 函    數:PCA9685讀寄存器
  46.   * 參    數:RegAddress 寄存器地址,范圍:參考PCA9685手冊的寄存器描述
  47.   * 返 回 值:讀取寄存器的數據,范圍:0x00~0xFF
  48.   */
  49. uint8_t PCA9685_ReadReg(uint8_t RegAddress)
  50. {
  51.         uint8_t Data;
  52.        
  53.         MyI2C_Start();                                                //I2C起始
  54.         MyI2C_SendByte(ADDRESS);                        //發送從機地址,讀寫位為0,表示即將寫入
  55.         MyI2C_ReceiveAck();                                        //接收應答
  56.         MyI2C_SendByte(RegAddress);                        //發送寄存器地址
  57.         MyI2C_ReceiveAck();                                        //接收應答
  58.        
  59.         MyI2C_Start();                                                //I2C重復起始
  60.         MyI2C_SendByte(ADDRESS | 0x01);                //發送從機地址,讀寫位為1,表示即將讀取
  61.         MyI2C_ReceiveAck();                                        //接收應答
  62.         Data = MyI2C_ReceiveByte();                        //接收指定寄存器的數據
  63.         MyI2C_SendAck(1);                                        //發送應答,給從機非應答,終止從機的數據輸出
  64.         MyI2C_Stop();                                                //I2C終止
  65.        
  66.         return Data;
  67. }

  68. //u8 PCA9685_Read(u8 addr)                //   addr 表示要讀取數據的寄存器地址
  69. //{
  70. //        u8 data;                           //   聲明一個無符號 8 位整數變量 data,用于存儲讀取到的數據。
  71. //        IIC_Start();                       //   發送 I2C 起始信號,開始 I2C 通信。
  72. //        IIC_Send_Byte(PCA_Addr);           //   發送 PCA_Addr = 0x80 ,告訴設備我們要寫入數據
  73. //        IIC_NAck();                        //   發送不應答信號,表示主控器不需要從設備接收更多數據。
  74. //        IIC_Send_Byte(addr);                  //   發送要讀取數據的寄存器地址。
  75. //        IIC_NAck();                           //   發送不應答信號。
  76. //        IIC_Stop();                           //   發送 I2C 停止信號,結束本次通信。
  77. //        delay_us(10);                         //   延時 10 微秒,等待芯片準備好數據。
  78. //        IIC_Start();                          //   發送 I2C 起始信號,開始另一次 I2C 通信。
  79. //        IIC_Send_Byte(PCA_Addr|0x01);         //   發送 PCA9685 的地址,并設置最低位為 1,
  80. //        IIC_NAck();                           //   發送不應答信號。
  81. //        data = IIC_Read_Byte(0);              //   通過 I2C 從 PCA9685 讀取一個字節的數據,并存儲到變量 data 中。
  82. //        IIC_Stop();                           //   發送 I2C 停止信號,結束本次通信。
  83. //        return data;                          //   返回讀取到的數據。
  84. //}

  85. /**
  86.   * 函    數:PCA9685設置輸出頻率
  87.   * 參    數:float 頻率
  88.   * 返 回 值:返回預分頻的值
  89. */
  90. void PCA9685_SetFreq(float freq)
  91. {
  92.         uint8_t prescale,oldmode,newmode;               //定義了三個無符號 8 位整型變量 用于存儲預分頻器值、舊的模式寄存器值和新的模式寄存器值
  93.         float prescaleval;                        //定義了一個雙精度浮點型變量 prescaleval,用于計算預分頻器的值。
  94.        
  95. //        freq *= 0.98;                             //將傳入的頻率值乘以 0.98,這是為了微調頻率值以適應 PCA9685 的實際需求       
  96.         prescaleval = 25000000/4096/freq - 1;
  97.         prescale = floor(prescaleval+0.5);       //將計算得到的預分頻器值四舍五入取整,并將其賦值給 prescale 變量。
  98.        
  99.         oldmode = PCA9685_ReadReg(MODE1);        //通過調用 PCA9685_Read 函數讀取當前 PCA9685 寄存器中的模式值,并將其存儲在 oldmode 變量中。
  100.        
  101.         newmode = (oldmode&0x7F)|0x10;            //根據舊的模式值計算出新的模式值,將最高位清零(不復位)并將第5位設為1,表示將 PCA9685 設置為睡眠模式。
  102.         PCA9685_WriteReg(MODE1,newmode);         //將新的模式值寫入 PCA9685 的模式寄存器。
  103.         PCA9685_WriteReg(PRE_SCALE,prescale);          //將計算得到的預分頻器值寫入 PCA9685 的預分頻器寄存器。
  104.         PCA9685_WriteReg(MODE1,oldmode);         //恢復舊的模式值。
  105.         Delay_us(500);                              // 延時 0.5 毫秒,等待 PCA9685 完全啟動。
  106.         PCA9685_WriteReg(MODE1,PCA9685_ReadReg(MODE1)|0x80);       //將模式值的第8( Restart enabled.).更新頻率后復位使用
  107.        
  108. }

  109. //void PCA9685_setFreq(float freq)
  110. //{
  111. //        u8 prescale,oldmode,newmode;               //定義了三個無符號 8 位整型變量 用于存儲預分頻器值、舊的模式寄存器值和新的模式寄存器值
  112. //          
  113. //        double prescaleval;                        //定義了一個雙精度浮點型變量 prescaleval,用于計算預分頻器的值。
  114. //       
  115. //        freq *= 0.98;                             //將傳入的頻率值乘以 0.98,這是為了微調頻率值以適應 PCA9685 的實際需求
  116. //        prescaleval = 25000000;                   //這是 PCA9685 內部振蕩器的頻率
  117. //        prescaleval /= 4096;                      //每個周期從0計數到4095,除以 4096,得到每個計數器周期的時間,
  118. //        prescaleval /= freq;                      //除以所需的頻率值,得到預分頻器的值。
  119. //        prescaleval -= 1;                         //減去 1,得到最終的預分頻器值
  120. //        prescale = floor(prescaleval+0.5f);       //將計算得到的預分頻器值四舍五入取整,并將其賦值給 prescale 變量。
  121. //        oldmode = PCA9685_Read(PCA_Model);        //通過調用 PCA9685_Read 函數讀取當前 PCA9685 寄存器中的模式值,并將其存儲在 oldmode 變量中。
  122. //       
  123. //        newmode = (oldmode&0x7F)|0x10;            //根據舊的模式值計算出新的模式值,將最高位清零(bit 7)并將第 5 位設為1(bit 4),表示將 PCA9685 設置為睡眠模式。
  124. //        PCA9685_Write(PCA_Model,newmode);         //將新的模式值寫入 PCA9685 的模式寄存器。
  125. //        PCA9685_Write(PCA_Pre,prescale);          //將計算得到的預分頻器值寫入 PCA9685 的預分頻器寄存器。
  126. //        PCA9685_Write(PCA_Model,oldmode);         //恢復舊的模式值。
  127. //        delay_ms(5);                              // 延時 5 毫秒,等待 PCA9685 完全啟動。
  128. //        PCA9685_Write(PCA_Model,oldmode|0xa1);    //將模式值的最高位和第 1 位設為1,表示將 PCA9685 設置為正常工作模式。
  129. //       
  130. //}

  131. /**
  132.   * 函    數:PCA9685_SetChannel
  133.   * 參    數:0~15
  134.   * 返 回 值:無
  135. */
  136. void PCA9685_SetChannel(uint8_t Channel)
  137. {
  138.         Channel_Flag = Channel;
  139. }

  140. /**
  141.   * 函    數:PCA9685_setPWM
  142.   * 參    數:channel;舵機編號。on 表示置1的位置,off 表示置0位置(12位有效,值要小于4095)
  143.   * 返 回 值:無
  144. */
  145. void PCA9685_SetPWM(uint16_t pulse_on,uint16_t pulse_off)  
  146. {
  147.         // 將脈沖寬度分解為ON和OFF時間
  148.     uint8_t on_l = (pulse_on & 0xFF);                                //低8位
  149.     uint8_t on_h = (pulse_on >> 8) & 0xFF;                        //高8位
  150.     uint8_t off_l = (pulse_off & 0xFF);
  151.     uint8_t off_h = (pulse_off >> 8) & 0xFF;

  152.     // 寫入ON和OFF時間到對應的寄存器
  153.     PCA9685_WriteReg(LED0_ON_L + 4 * Channel_Flag, on_l);
  154.     PCA9685_WriteReg(LED0_ON_H + 4 * Channel_Flag, on_h);
  155.     PCA9685_WriteReg(LED0_OFF_L + 4 * Channel_Flag, off_l);
  156.     PCA9685_WriteReg(LED0_OFF_H + 4 * Channel_Flag, off_h);
  157. }
  158. //void PCA9685_setPWM(u8 num,u32 on,u32 off)   //num 表示 PWM 通道號,on 表示 PWM 的起始位置,off 表示 PWM 的結束位置(即從高電平切換到低電平的時刻)
  159. //{
  160. //        IIC_Start();                              //發送 I2C 起始信號,開始 I2C 通信。
  161. //       
  162. //        IIC_Send_Byte(PCA_Addr);                  //發送 PCA9685 的地址,告訴設備我們要和 PCA9685 進行通信。
  163. //        IIC_Wait_Ack();                           //等待應答信號,確保設備準備好接收數據。
  164. //
  165. //        IIC_Send_Byte(LED0_ON_L+4*num);           //發送 LED 寄存器的地址,根據 PWM 通道號計算出相應的寄存器地址。
  166. //        IIC_Wait_Ack();                           //
  167. //       
  168. //        IIC_Send_Byte(on&0xFF);                   //發送 PWM 的起始位置低 8 位。
  169. //        IIC_Wait_Ack();                           //等待應答信號。
  170. //         
  171. //        IIC_Send_Byte(on>>8);                     //發送 PWM 的起始位置高 8 位。
  172. //        IIC_Wait_Ack();                           //等待應答信號。
  173. //       
  174. //        IIC_Send_Byte(off&0xFF);                  //發送 PWM 的結束位置低 8 位。
  175. //        IIC_Wait_Ack();                           //等待應答信號。
  176. //       
  177. //        IIC_Send_Byte(off>>8);                    //發送 PWM 的結束位置高 8 位。
  178. //        IIC_Wait_Ack();                           //等待應答信號。
  179. //       
  180. //        IIC_Stop();                              //發送 I2C 停止信號,結束本次通信。
  181. //}
  182. /**
  183.   * 函    數:SetAngle
  184.   * 參    數:0~180°
  185.   * 返 回 值:無
  186. */
  187. void PCA9685_SetAngle(uint8_t angle)
  188. {
  189.         uint16_t pulse_on = 0;
  190.         uint16_t pulse_off = 0;
  191.         pulse_off = (uint16_t)((angle+45)*4096/1800+0.5);  //四舍五入
  192.         PCA9685_SetPWM(pulse_on,pulse_off);
  193. }

  194. //void setAngle(u8 num,u16 angle)
  195. //{
  196. //        u32 off = 0;               
  197. //        off = (u32)(103+angle*1.13);  //360度舵機,每轉動一度=1.14   0.5ms -180度起始位置:103
  198. //        PCA9685_setPWM(num,0,angle);
  199. //}
  200. //
  201. //

  202. /**
  203.   * 函    數:PCA9685初始化
  204.   * 參    數:無
  205.   * 返 回 值:無
  206.   */
  207. void PCA9685_Init(void)
  208. {
  209.         MyI2C_Init();                                                                        //先初始化底層的I2C
  210.        
  211.         /*PCA9685寄存器初始化,需要對照PCA9685手冊的寄存器描述配置,此處僅配置了部分重要的寄存器*/
  212.         PCA9685_WriteReg(MODE1, 0x21);                                        //0使用內部時鐘,1自增模式,0退出睡眠模式,1響應0x70通用地址
  213.         Delay_us(500);                                      // 延時 0.5 毫秒,等待 PCA9685 完全啟動。
  214.        
  215. }
  216. //  
  217. //
  218. //void PCA9685_Init(float hz,u16 angle)
  219. //{
  220. //        u32 off = 0;
  221. //        IIC_Init();
  222. //        PCA9685_Write(PCA_Model,0x00);
  223. //        PCA9685_setFreq(hz);
  224. //    off = (u32)(103+angle*1.14);  //360度舵機,每轉動一度=1.14    0.5ms -180度起始位置:103
  225. //        PCA9685_setPWM(0,0,off);
  226. //        PCA9685_setPWM(1,0,off);
  227. //        PCA9685_setPWM(2,0,off);
  228. //        PCA9685_setPWM(3,0,off);
  229. //        PCA9685_setPWM(4,0,off);
  230. //        PCA9685_setPWM(5,0,off);
  231. //        PCA9685_setPWM(6,0,off);
  232. //        PCA9685_setPWM(7,0,off);
  233. //        PCA9685_setPWM(8,0,off);
  234. //        PCA9685_setPWM(9,0,off);
  235. //        PCA9685_setPWM(10,0,off);
  236. //        PCA9685_setPWM(11,0,off);
  237. //        PCA9685_setPWM(12,0,off);
  238. //        PCA9685_setPWM(13,0,off);
  239. //        PCA9685_setPWM(14,0,off);
  240. //        PCA9685_setPWM(15,0,off);
  241. //        delay_ms(100);
  242. //       
  243. //}
  244. /**
  245.   * 函    數:Channel函數,串口選擇指定通道
  246.   * 參    數:無
  247.   * 返 回 值:無
  248.   */
  249. void Channel(void)
  250. {
  251.         Serial_SendString("Run_16_Servo...\r\n");                                //串口回傳一個字符串
  252.         OLED_Clear();
  253.         OLED_ShowString(1, 1, "Run_16_Servo.");                                //OLED清除指定位置,并顯示Run_Mode_1
  254.         OLED_ShowString(2, 1, "Channel;");
  255.         Serial_RxFlag = 0;                                //進入循環前,結束數據包處理,等待接受命令
  256.        
  257.         while (1)
  258.         {
  259.                 if (Serial_RxFlag == 1)                       
  260.                 {
  261.                         if (strcmp(Serial_RxPacket, "Stop") == 0)                         //傳入Stop字符停止當前模式
  262.                         {
  263.                                 Serial_SendString("Stop_Channel...\r\n");                               
  264.                                 OLED_Clear();
  265.                                 OLED_ShowString(1, 1, "Stop_Channel.");
  266.                                 Serial_RxFlag = 0;
  267.                                 break;
  268.                         }
  269.                         else                                                                                        
  270.                         {
  271.                                 uint8_t Channel  = atoi(Serial_RxPacket);                                //把字符串轉為數字
  272.                                 PCA9685_SetChannel(Channel);                                                                //置通道
  273.                                 OLED_ShowNum(2, 9, Channel, 2);
  274.                                 OLED_ShowString(3, 1, "Angle;");
  275.                                 Serial_Printf("Channel;%d", Channel);
  276.                                 Serial_RxFlag = 0;                                                                //數據包接收標志位清零等待下次接收
  277.                                 break;
  278.                         }
  279.                 }
  280.         }
  281. }
  282. /**
  283.   * 函    數:Angle函數,串口選擇指定角度
  284.   * 參    數:無
  285.   * 返 回 值:無
  286.   */
  287. void Angle(void)
  288. {
  289.         while (1)
  290.         {
  291.                 if (Serial_RxFlag == 1)                       
  292.                 {
  293.                         if (strcmp(Serial_RxPacket, "Stop") == 0)                         //傳入Stop字符停止當前模式
  294.                         {
  295.                                 Serial_SendString("Stop_16_Servo...\r\n");                               
  296.                                 OLED_Clear();
  297.                                 OLED_ShowString(1, 1, "Stop_16_Servo.");
  298.                                 Serial_RxFlag = 0;
  299.                                 break;
  300.                         }
  301.                         else                                                                                                 //否則認為輸入的是角度
  302.                         {
  303.                                 uint8_t Angle  = atoi(Serial_RxPacket);                                //把字符串轉為數字
  304.                                 PCA9685_SetAngle(Angle);                                                                //置角度
  305.                                 OLED_ShowNum(3, 7, Angle, 3);
  306.                                 Serial_Printf("Angle;%d", Angle);
  307.                                 Serial_RxFlag = 0;                                                                //數據包接收標志位清零等待下次接收
  308.                         }
  309.                 }
  310.         }
  311. }
復制代碼



#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "LED.h"
#include "string.h"
#include "Servo.h"
#include "PCA9685.h"

int main(void)
{
        /*模塊初始化*/
        OLED_Init();                //OLED初始化
        Serial_Init();                //串口初始化
        PCA9685_Init();
        PCA9685_SetFreq(50);

        while (1)
        {
                if (Serial_RxFlag == 1)                //如果接收到數據包
                {
                        if (strcmp(Serial_RxPacket, "16_Servo") == 0)                        
                        {
                                Channel();
                                Angle();
                        }
                        Serial_RxFlag = 0;                        //防止串口錯誤輸入導致標志位一直不清零,不能接收下次指令
                }
        }
}


原理圖: 無
仿真: 無
代碼: 程序.7z (187.3 KB, 下載次數: 0)

評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 天天干狠狠 | 国产日韩欧美二区 | 日本黄色激情视频 | 性色av网站| 亚洲精品一区国语对白 | 日韩一区二区三区在线观看视频 | 国产精品久久久久久二区 | 国产伦一区二区三区四区 | 久久久久国产精品一区二区 | 国产欧美一区二区三区在线看蜜臀 | 国产成人叼嘿视频在线观看 | 欧美性大战久久久久久久蜜臀 | 国产一区二区三区久久久久久久久 | 亚洲www啪成人一区二区 | caoporon| jlzzjlzz欧美大全 | 日本精品一区二区三区四区 | 中文字幕在线视频一区二区三区 | 国产91精品网站 | 99精品电影| 日本精品视频 | 一级在线免费观看 | 精品在线一区 | 在线天堂免费中文字幕视频 | 色偷偷噜噜噜亚洲男人 | 午夜欧美 | 亚洲香蕉在线视频 | 91高清视频在线观看 | 日韩精品一区在线观看 | 国产精品夜色一区二区三区 | 黄色日本片 | 麻豆久久 | 免费人成在线观看网站 | 成人在线中文字幕 | 亚洲高清在线观看 | 1204国产成人精品视频 | 一级黄色片日本 | av性色 | 亚洲一区在线日韩在线深爱 | 国产精品乱码一区二区三区 | 欧美激情久久久久久 |