欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
注釋stm32單片機之串口1解析控制舵機程序
[打印本頁]
作者:
13570972050
時間:
2021-9-26 22:30
標題:
注釋stm32單片機之串口1解析控制舵機程序
一款機械臂程序分享
/***************************************************************
@筆者:tacbo
功能列表:
1、單個舵機控制(支持PWM舵機和總線舵機)
2、多個舵機控制(支持PWM舵機和總線舵機)
3、手柄控制舵機
4、串口控制舵機
5、OLED顯示舵機的執行情況
6、USB一鍵下載
7、可支持總線MP3 總線WIFI等設備
8、上位機圖形化編程
9、控制6自由度機械臂
***************************************************************/
#include "tb_rcc.h" //配置時鐘文件
#include "tb_gpio.h" //配置IO口文件
#include "tb_global.h" //存放全局變量
#include "tb_delay.h" //存放延時函數
#include "tb_type.h" //存放類型定義
#include "tb_usart.h" //存放串口功能文件
#include "tb_timer.h" //存放定時器功能文件
#include "ADC.h" //存放ADC的
#include "PS2_SONY.h" //存放索尼手柄
#include "w25q64.h" //存儲芯片的操作
#include "oled_i2c.h" //OLED文件
#include <stdio.h> //標準庫文件
#include <string.h> //標準庫文件
#include <math.h> //標準庫文件
#define VERSION 20170919 //版本定義
#define CYCLE 1000 //PWM模塊周期
#define PS2_LED_RED 0x73 //PS2手柄紅燈模式
#define PS2_LED_GRN 0x41 //PS2手柄綠燈模式
#define PSX_BUTTON_NUM 16 //手柄按鍵數目
#define PS2_MAX_LEN 64 //手柄命令最大字節數
#define FLAG_VERIFY 0x25 //校驗標志
#define ACTION_SIZE 0x80 //一個動作的存儲大小
#define W25Q64_INFO_ADDR_SAVE_STR (((8<<10)-2)<<10)//(8*1024-1)*1024 //eeprom_info結構體存儲的位置
void system_init(void); //系統初始化
void beep_led_dis_init(void); //開機提示
void handle_nled(void); //LED工作指示燈提示
void soft_reset(void); //軟件復位
void car_pwm_set(int car_left, int car_right); //電機控制函數
void handle_ps2(void); //手柄數據解析
void handle_button(void); //手柄按鍵解析
void parse_psx_buf(unsigned char *buf, unsigned char mode); //手柄按鍵解析子函數
void handle_car(void); //搖桿數據解析控制車
void handle_uart(void); //串口解析
void parse_cmd(u8 *cmd); //命令解析
void action_save(u8 *str); //動作保存函數
int get_action_index(u8 *str); //獲取動作組序號
void print_group(int start, int end); //打印動作組
void int_exchange(int *int1, int *int2); //兩個int互換
void do_group_once(int group_num); //執行動作組1次
void handle_action(void); //處理動作組執行
u8 check_dj_state(void); //獲取舵機的狀態
void do_action(u8 *uart_receive_buf); //執行動作
void replace_char(u8*str, u8 ch1, u8 ch2); //字符串字母替換
void rewrite_eeprom(void); //寫入eeprom_info結構體
void handle_adc(void); //處理ADC數據
void handle_oled(void); //處理OLED數據
u8 psx_buf[9]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //存儲手柄的數據
const char *pre_cmd_set_red[PSX_BUTTON_NUM] = { //紅燈模式下按鍵的配置
"<PS2_RED01:#005P0600T2000!^$DST:5!>", //L2
"<PS2_RED02:#005P2400T2000!^$DST:5!>", //R2
"<PS2_RED03:#004P0600T2000!^$DST:4!>", //L1
"<PS2_RED04:#004P2400T2000!^$DST:4!>", //R1
"<PS2_RED05:#002P2400T2000!^$DST:2!>", //RU
"<PS2_RED06:#003P0600T2000!^$DST:3!>", //RR
"<PS2_RED07:#002P0600T2000!^$DST:2!>", //RD
"<PS2_RED08:#003P2400T2000!^$DST:3!>", //RL
"<PS2_RED09:$DJ_RECORD_DO:1!>", //SE 執行1次
"<PS2_RED10:$DJ_RECORD_CLEAR!>", //AL 清除
"<PS2_RED11:$DJ_RECORD!>", //AR 學習
"<PS2_RED12:$DJR!>", //ST
"<PS2_RED13:#001P0600T2000!^$DST:1!>", //LU
"<PS2_RED14:#000P0600T2000!^$DST:0!>", //LR
"<PS2_RED15:#001P2400T2000!^$DST:1!>", //LD
"<PS2_RED16:#000P2400T2000!^$DST:0!>", //LL
};
const char *pre_cmd_set_grn[PSX_BUTTON_NUM] = { //綠燈模式下按鍵的配置
"<PS2_GRN01:$!>", //L2
"<PS2_GRN02:$!>", //R2
"<PS2_GRN03:$!>", //L1
"<PS2_GRN04:$!>", //R1
"<PS2_GRN05:$!>", //RU
"<PS2_GRN06:$!>", //RR
"<PS2_GRN07:$!>", //RD
"<PS2_GRN08:$!>", //RL
"<PS2_GRN09:$!>", //SE
"<PS2_GRN10:$!>", //AL-NO
"<PS2_GRN11:$!>", //AR-NO
"<PS2_GRN12:$!>", //ST
"<PS2_GRN13:$!>", //LU
"<PS2_GRN14:$!>", //LR
"<PS2_GRN15:$!>", //LD
"<PS2_GRN16:$!>", //LL
};
/*"D:\DreamSpark\OLED\MP3_UI.bmp",0 圖片取模數據
unsigned char MY_PIC[] = {
0x00,0x03,0x05,0x09,0x11,0xFF,0x11,0x89,0x05,0xC3,0x00,0xE0,0x00,0xF0,0x00,0xF8,
*************************
0x80,0xFF,0x80,0xEE,0xEE,0xEE,0xF5,0xFB,0xFF,0x9C,0xBE,0xB6,0xB6,0x88,0xFF,0x00,
};
*/
int i; //常用的一個臨時變量
u8 car_dw = 1; //搖桿檔位控制
u8 group_do_ok = 1; //動作執行完成標志
int do_start_index; //動作組執行 起始序號
int do_time; //動作組執行 執行次數
int group_num_start; //動作組執行 起始序號
int group_num_end; //動作組執行 終止序號
int group_num_times; //動作組執行 起始變量
u32 dj_record_time = 1000; //學習時間默認1000
/*-------------------------------------------------------------------------------------------------------
* 程序從這里執行
* 這個啟動代碼 完成時鐘配置 使用外部晶振作為STM32的運行時鐘 并倍頻到72M最快的執行速率
-------------------------------------------------------------------------------------------------------*/
int main(void)
{
tb_rcc_init(); ///時鐘初始化 已經備注
tb_gpio_init(); ///IO初始化 打開時鐘
tb_global_init(); //全局變量初始化
nled_init(); ///工作指示燈初始化
// beep_init(); ///蜂鳴器初始化
dj_io_init(); ///舵機IO口初始化
//w25q64 init
W25Q_Init(); //動作組存儲芯片初始化
if(W25Q_TYPE != W25Q64){ //判斷是否是W25Q64芯片
while(1)beep_on(); //如果不是則長鳴,說明芯片有問題,無法通信
}
W25Q_Read((u8 *)(&eeprom_info), W25Q64_INFO_ADDR_SAVE_STR, sizeof(eeprom_info)); //讀取全局變量
if(eeprom_info.version != VERSION) { //判斷版本是否是當前版本
eeprom_info.version = VERSION; //復制當前版本
eeprom_info.dj_record_num = 0; //學習動作組變量賦值0
rewrite_eeprom(); //寫入到存儲器 ///把結構體里面的內容讀取處理 然后再把內容寫進去
}
//ADC_init(); ///ADC初始化
//PSX_init(); //手柄初始化 GPIO
TIM2_Int_Init(20000, 71); ///舵機 定時器初始化 定時器中斷輸出高電平
///小車 pwm 初始化 利用了高級定時器 PWM引腳輸出
TIM3_Pwm_Init(1000, 239);
TIM4_Pwm_Init(1000, 239);
car_pwm_set(0,0); //設置小車的左右輪速度為0
//串口1初始化
tb_usart1_init(115200); //配置結構體,不包括使能串口
uart1_open(); //打開串口中斷
//串口2初始化
tb_usart2_init(115200);
uart2_open();
//串口3初始化
tb_usart3_init(115200);
uart3_open();
//總中斷打開
tb_interrupt_open();
//三個串口發送測試字符
uart1_send_str((u8 *)"uart1 check ok!");
uart2_send_str((u8 *)"uart2 check ok!");
uart3_send_str((u8 *)"uart3 check ok!");
//總線輸出 復位總線舵機
zx_uart_send_str((u8 *)"#255P1500T2000!");
//系統滴答時鐘初始化
SysTick_Int_Init();
//蜂鳴器LED 名叫閃爍 示意系統啟動
beep_led_dis_init();
//執行預存命令
if(eeprom_info.pre_cmd[PRE_CMD_SIZE] == FLAG_VERIFY) {
if(eeprom_info.pre_cmd[0] == '
) {
memset(uart_receive_buf, 0, sizeof(uart_receive_buf));
strcpy((char *)uart_receive_buf, (char *)eeprom_info.pre_cmd);///把儲存的數據讀取出來
uart1_mode = 1;
uart1_get_ok = 1;
uart1_send_str(uart_receive_buf);
}
}
//OLED初始化
//OLED_Init();
while(1) //parse_cmd(uart_receive_buf); //解析命令模式 串口改變變量和按鍵 公用這個函數 解析動作,解析動作只是改變舵機的變量,舵機控制在中斷函數
{
handle_nled(); //處理信號燈 ///利用系統內部定時器SysTick
handle_ps2(); //處理手柄 初始化 把手柄的數據讀取出來
handle_button(); //處理手柄按鈕 //do_action(uart_receive_buf); 獲取按鍵狀態 控制舵機
handle_car(); //處理搖桿控制小車
handle_uart(); //處理串口接收數據 //定義一個指針,可以被多個函數調用 中斷接收串口數據 do_action(uart_receive_buf);
handle_action(); //處理動作組 main 865
handle_adc(); //處理ADC
handle_oled(); //處理OLED顯示
}
}
//開機指示函數,蜂鳴器和工作指示燈鳴3聲作為開機指示
void beep_led_dis_init(void) {
beep_on();nled_on();tb_delay_ms(100);beep_off();nled_off();tb_delay_ms(100);
beep_on();nled_on();tb_delay_ms(100);beep_off();nled_off();tb_delay_ms(100);
beep_on();nled_on();tb_delay_ms(100);beep_off();nled_off();tb_delay_ms(100);
}
///工作指示燈處理,間隔1000MS閃爍一次
void handle_nled(void) {
static u32 time_count=0;
static u8 flag = 0;
if(systick_ms-time_count > 1000) {
time_count = systick_ms;
if(flag) {
nled_on();
} else {
nled_off();
}
flag= ~flag;
}
}
//軟件復位函數,調用后單片機自動復位
void soft_reset(void) {
__set_FAULTMASK(1);
NVIC_SystemReset();
}
//小車控制函數
//參數 左輪速度和右輪速度 范圍 -1000 到 1000
void car_pwm_set(int car_left, int car_right) {
if(car_left >= CYCLE)car_left = CYCLE-1;
else if(car_left <= -CYCLE)car_left = -CYCLE+1;
else if(car_left == 0)car_left = 1;
if(car_right >= CYCLE)car_right = CYCLE-1;
else if(car_right <= -CYCLE)car_right = -CYCLE+1;
else if(car_right == 0)car_right = 1;
//car_left = car_left/car_dw;
//car_right = car_right/car_dw;
if(car_right>0) {
TIM_SetCompare4(TIM4,1);
TIM_SetCompare3(TIM4,car_right); ///設置CCR,初始化已經設置的CCR沒影響 占空比
}
else
{
TIM_SetCompare4(TIM4,-car_right);
TIM_SetCompare3(TIM4,1);
}
if(car_left>0)
{
TIM_SetCompare4(TIM3,1);
TIM_SetCompare3(TIM3,car_left); ///設置占空比 CCR PWM比較寄存器
}
else
{
TIM_SetCompare4(TIM3,-car_left);
TIM_SetCompare3(TIM3,1);
}
// //總線馬達設置
// sprintf((char *)cmd_return, "#0233P%dT0!#034P%dT0!",
// (int)(1500+car_left), (int)(1500+car_right));
// zx_uart_send_str(cmd_return);
return;
}
//處理手柄
void handle_ps2(void)
{
static u32 systick_ms_bak = 0;
//每20ms處理1次
if(systick_ms - systick_ms_bak < 20)
{
return;
}
systick_ms_bak = systick_ms;
//讀寫手柄數據
psx_write_read(psx_buf); //把psx buf數據處理
#if 0
//測試手柄數據,1為打開 0為關閉
sprintf((char *)cmd_return, "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\r\n",
(int)psx_buf[0], (int)psx_buf[1], (int)psx_buf[2], (int)psx_buf[3],
(int)psx_buf[4], (int)psx_buf[5], (int)psx_buf[6], (int)psx_buf[7], (int)psx_buf[8]);
uart1_send_str(cmd_return);
#endif
return;
}
//處理手柄按鍵
void handle_button(void)
{
static unsigned char psx_button_bak[2] = {0};///首先對這個數組清空
//對比兩次獲取的按鍵值是否相同 ,相同就不處理,不相同則處理
if((psx_button_bak[0] == psx_buf[3]) //psx buf 是已經獲取的值
&& (psx_button_bak[1] == psx_buf[4]))
{
}
else {
//處理buf3和buf4兩個字節,這兩個字節存儲這手柄16個按鍵的狀態
parse_psx_buf(psx_buf+3, psx_buf[1]); ///獲取狀態 把按鍵獲取的數值 輸入到函數處理
psx_button_bak[0] = psx_buf[3];//把這兩個值 放入到數組
psx_button_bak[1] = psx_buf[4];
}
return;
}
//處理手柄按鍵字符,buf為字符數組,mode是指模式 主要是紅燈和綠燈模式 獲取按鈕狀態
void parse_psx_buf(unsigned char *buf, unsigned char mode) ///mode就是紅燈或者綠燈
{
u8 i, pos = 0;
static u16 bak=0xffff, temp, temp2;
temp = (buf[0]<<8) + buf[1];
if(bak != temp)
{
temp2 = temp;
temp &= bak;
for(i=0;i<16;i++) {//16個按鍵一次輪詢
if((1<<i) & temp)
{
}
else
{
if((1<<i) & bak)
{ //press 表示按鍵按下了
memset(uart_receive_buf, 0, sizeof(uart_receive_buf)); ///把數組清空
if(mode == PS2_LED_RED)
{
memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_red[i], strlen(pre_cmd_set_red[i]));
}
else if(mode == PS2_LED_GRN)
{
memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_grn[i], strlen(pre_cmd_set_grn[i]));
} //把按下的按鍵對應的數值傳遞給接收數組 用來解析
else continue;
pos = str_contain_str(uart_receive_buf, (u8 *)"^"); ///通過按鍵 解析模式
if(pos)
uart_receive_buf[pos-1] = '\0';
if(str_contain_str(uart_receive_buf, (u8 *)"[ DISCUZ_CODE_0 ]quot;)) //命令模式
{
uart1_close();
uart1_get_ok = 0;
strcpy((char *)cmd_return, (char *)uart_receive_buf+11);
strcpy((char *)uart_receive_buf, (char *)cmd_return);
uart1_get_ok = 1;
uart1_open();
uart1_mode = 1;
}
else if(str_contain_str(uart_receive_buf, (u8 *)"#"))
{
uart1_close();
uart1_get_ok = 0;
strcpy((char *)cmd_return, (char *)uart_receive_buf+11);
strcpy((char *)uart_receive_buf,(char *) cmd_return);
uart1_get_ok = 1;
uart1_open();
uart1_mode = 2;
}
//uart1_send_str(uart_receive_buf);
bak = 0xffff;
} else {//release 表示按鍵松開了
memset(uart_receive_buf, 0, sizeof(uart_receive_buf));
if(mode == PS2_LED_RED) {
memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_red[i], strlen(pre_cmd_set_red[i]));
} else if(mode == PS2_LED_GRN) {
memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_grn[i], strlen(pre_cmd_set_grn[i]));
} else continue;
pos = str_contain_str(uart_receive_buf, (u8 *)"^");
if(pos) {
if(str_contain_str(uart_receive_buf+pos, (u8 *)"[ DISCUZ_CODE_0 ]quot;)) {
//uart1_close();
//uart1_get_ok = 0;
strcpy((char *)cmd_return, (char *)uart_receive_buf+pos);
cmd_return[strlen((char *)cmd_return) - 1] = '\0';
strcpy((char *)uart_receive_buf, (char *)cmd_return);
parse_cmd(uart_receive_buf);
//uart1_get_ok = 1;
//uart1_mode = 1;
} else if(str_contain_str(uart_receive_buf+pos, (u8 *)"#")) {
//uart1_close();
//uart1_get_ok = 0;
strcpy((char *)cmd_return, (char *)uart_receive_buf+pos);
cmd_return[strlen((char *)cmd_return) - 1] = '\0';
strcpy((char *)uart_receive_buf, (char *)cmd_return);
do_action(uart_receive_buf);
//uart1_get_ok = 1;
//uart1_mode = 2;
}
//uart1_send_str(uart_receive_buf);
}
}
}
}
bak = temp2;
beep_on();mdelay(10);beep_off();
}
return;
}
//int型 取絕對值函數
int abs_int(int int1) {
if(int1 > 0)return int1;
return (-int1);
}
//處理小車函數 主要處理搖桿的數據 這里 8為左搖桿 6為右搖桿
void handle_car(void)
{
static int car_left, car_right, car_left_bak, car_right_bak;
if(psx_buf[1] != PS2_LED_RED)return;
if(abs_int(127 - psx_buf[8]) < 5 )
psx_buf[8] = 127;
if(abs_int(127 - psx_buf[6]) < 5 )
psx_buf[6] = 127;
car_left = (127 - psx_buf[8]) * 8;
car_right = (127 - psx_buf[6]) * 8;
// if(abs_int(car_left_bak-car_left) < 20 && abs_int(car_right_bak-car_right) < 20)return;
// if(abs_int(car_left_bak-car_left) > 40)car_left_bak = car_left;
// if(abs_int(car_right_bak-car_right) > 40)car_right_bak = car_right;
if(car_left != car_left_bak || car_right != car_right_bak)
{
car_pwm_set(car_left, car_right); ///把速度傳送到定時器PWM寄存器
car_left_bak = car_left;
car_right_bak = car_right;
}
}
//處理串口接收到的數據 ///首先通過中斷獲取串口的數據
void handle_uart(void)
///串口接收中斷,判斷中斷標志位,進入中斷函數,把數據保存在數組,判斷數組內容,返回uart1_get_ok
///當接收到數據之后,馬上執行串口解析動作,判斷數據,執行動作
{
if(uart1_get_ok)
{
if(uart1_mode == 1) //命令模式
{
//uart1_send_str("cmd:");
//uart1_send_str(uart_receive_buf);
parse_cmd(uart_receive_buf); //解析命令模式
}
else if(uart1_mode == 2) ///單個命令 只有一種模式
{ //單個舵機調試
//uart1_send_str("sig:");
//uart1_send_str(uart_receive_buf);
do_action(uart_receive_buf); ///處理接收數據內容
}
else if(uart1_mode == 3)
{ //多路舵機調試
//uart1_send_str("group:");
//uart1_send_str(uart_receive_buf);
do_action(uart_receive_buf);
}
else if(uart1_mode == 4)
{ //存儲模式
//uart1_send_str("save:");
//uart1_send_str(uart_receive_buf);
action_save(uart_receive_buf);
}
uart1_mode = 0;
uart1_get_ok = 0;
}
return;
}
/*
所有舵機停止命令:$DST!
第x個舵機停止命令:$DST:x!
單片機重啟命令:$RST!
檢查動作組x到y組命令:$CGP:x-y!
執行第x個動作:$DGS:x!
執行第x到y組動作z次:$DGT:x-y,z!
小車左輪x速度,右輪y速度:$DCR:x,y!
所有舵機復位命令:$DJR!
獲取應答信號:$GETA!
*/
//命令解析函數
void parse_cmd(u8 *cmd)
{
int pos, i, index, int1, int2;
u8 temp_buf[160];
u32 long1;
//uart1_send_str(cmd);
if(pos = str_contain_str(uart_receive_buf, (u8 *)"$DST!"), pos) ///接收信息比較 所有舵機停止命令:$DST!
{
group_do_ok = 1; //動作執行完成標志
for(i=0;i<DJ_NUM;i++) ///停止舵機
……………………
…………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
代碼下載:
注釋stm32單片機之串口1解析控制舵機.7z
(1.18 MB, 下載次數: 10)
2021-9-26 23:03 上傳
點擊文件名下載附件
閱讀權限: 255
下載積分: 黑幣 -5
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1