找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5936|回复: 2
收起左侧

功能很多的单片机智能小车源码(PS2手柄控制+舵机+W25Q64存储)

[复制链接]
ID:356227 发表于 2018-8-29 01:00 | 显示全部楼层 |阅读模式
手柄序号分布.png 0.png

单片机源程序如下:
  1. /*
  2.         1、串口1调试                  ok
  3.         2、串口2调试                  ok
  4.         3、定时器0调试                ok
  5.         4、定时器1调试                ok
  6.         5、PS2手柄调试                ok
  7.         6、4通道PWM调试                ok
  8.         7、舵机调试                          ok
  9.         8、W25Q64存储调试        ok
  10.         
  11.         调试的过程:
  12.         如上,一个一个模块调通,最后组合
  13.         左边的目录结构就是正队每一个模块调试好做成一个模块文件,便于移植
  14.         
  15.         看程序方法:
  16.         看程序的时候,从main文件的main函数看起
  17.         基本的程序思路是
  18.         主函数->各个模块初始化->大循环while(1)
  19.                                                   ->中断(串口、定时器等)
  20.         大家在深究本程序时,建议大家先去了解各个模块的原理,然后看懂文件结构和程序结构,最后再细究算法问题
  21.         
  22.         智能传感器版本增加内容:
  23.         所需硬件
  24.         循迹模块 2个
  25.         超声波模块 1个
  26.         颜色识别模块 1个
  27.         声音模块 1个
  28.         木块红、蓝、绿各一个
  29.         
  30.         IO口分布
  31.         循迹左         P0^6
  32.         循迹右         P0^7
  33.         超声波         P1^6
  34.         颜色          P1^2
  35.         声音          P1^0
  36.         
  37.         智能识别功能(手柄绿灯模式 左边 上下左右 和 右边 上下左右)
  38.         
  39.         功能0 循迹模式
  40.         功能1 声控夹取
  41.         功能2 自由避障
  42.         功能3 颜色识别
  43.         功能4 定距夹取
  44.         功能5 跟随功能
  45.         功能6 循迹避障
  46.         功能7 循迹识别
  47.         功能8 循迹定距
  48.         
  49.         手动遥控功能
  50.         1、手柄遥控
  51.         2、APP遥控
  52.         3、WIFI遥控

  53.         图形化编程功能
  54.         
  55.         功能切换:绿灯模式下通过左边上下左右键切换功能,通过蜂鸣器的声音的响声播报功能
  56.         
  57. */
  58. //头文件
  59. #include <stdio.h>
  60. #include <string.h>
  61. #include "z_stc15.h"
  62. #include "z_main.h"
  63. #include "z_uart.h"
  64. #include "z_delay.h"
  65. #include "z_gpio.h"
  66. #include "z_ps2.h"
  67. #include "z_pwm.h"
  68. #include "z_timer.h"
  69. #include "z_w25q64.h"
  70. #include "z_global.h"
  71. #include "z_adc.h"
  72. #include "z_sensor.h"
  73. //定义些变量,关于变量的作用,可以查找下是哪里用到了,具体看在那里是什么作用
  74. u16 adc7_value = 0, adc0_value = 0;
  75. u16 do_start_index, do_time, group_num_start, group_num_end, group_num_times;
  76. u8 i;
  77. u8 car_dw = 1;
  78. u32 bias_systick_ms_bak = 0;
  79. u8 djBiasSaveFlag = 0;
  80. u8 dbt_flag = 0;
  81. float vol_adc = 0;u32 save_addr_sector = 0, save_action_index_bak = 0;
  82. u8 psx_buf[9]={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};         //存储手柄信息

  83. code const char *pre_cmd_set_red[PSX_BUTTON_NUM] = {
  84.         "<PS2_RED01:#005P0600T2000!^$DST!>",        //L2                                                  
  85.         "<PS2_RED02:#005P2400T2000!^$DST!>",        //R2                                                  
  86.         "<PS2_RED03:#004P0600T2000!^$DST!>",        //L1                                                  
  87.         "<PS2_RED04:#004P2400T2000!^$DST!>",        //R1                        
  88.         "<PS2_RED05:#002P2400T2000!^$DST!>",        //RU                                                  
  89.         "<PS2_RED06:#003P2400T2000!^$DST!>",        //RR                                                  
  90.         "<PS2_RED07:#002P0600T2000!^$DST!>",        //RD                                                  
  91.         "<PS2_RED08:#003P0600T2000!^$DST!>",        //RL                                
  92.         "<PS2_RED09:$!>",                                                           //SE                                      
  93.         "<PS2_RED10:$!>",                                                          //AL                                                   
  94.         "<PS2_RED11:$!>",                                                          //AR                                                  
  95.         "<PS2_RED12:$DJR!>",                                                //ST                        
  96.         "<PS2_RED13:#001P0600T2000!^$DST!>",        //LU                                                  
  97.         "<PS2_RED14:#000P0600T2000!^$DST!>",        //LR                                                                  
  98.         "<PS2_RED15:#001P2400T2000!^$DST!>",        //LD                                                  
  99.         "<PS2_RED16:#000P2400T2000!^$DST!>",        //LL                                                        
  100. };

  101. code const char *pre_cmd_set_grn[PSX_BUTTON_NUM] = {
  102.         "<PS2_GRN01:$!>",                                  //L2                                                  
  103.         "<PS2_GRN02:$!>",                                  //R2                                                  
  104.         "<PS2_GRN03:$!>",                                  //L1                                                  
  105.         "<PS2_GRN04:$!>",                                  //R1                        
  106.         "<PS2_GRN05:$SMODE5!>",                      //RU                                                  
  107.         "<PS2_GRN06:$SMODE8!>",                      //RR                                                  
  108.         "<PS2_GRN07:$SMODE6!>",                      //RD                                                  
  109.         "<PS2_GRN08:$SMODE7!>",                      //RL                                
  110.         "<PS2_GRN09:$SMODE0!>",                                              //SE                                             
  111.         "<PS2_GRN10:$!>",                                                          //AL                                          
  112.         "<PS2_GRN11:$!>",                                                          //AR                                          
  113.         "<PS2_GRN12:$DJR!>",                                                //ST                        
  114.         "<PS2_GRN13:$SMODE1!>",                      //LU                                                  
  115.         "<PS2_GRN14:$SMODE4!>",                      //LR                                                                  
  116.         "<PS2_GRN15:$SMODE2!>",                      //LD                                                  
  117.         "<PS2_GRN16:$SMODE3!>",                      //LL                                                  
  118. };


  119. code const char *action_pre_group[] = {
  120.     //动作生成数据为(可直接全选复制粘贴到程序中):
  121.     //偏差调节组
  122.     "{G0000#000P1500T1000!#001P1500T1000!#002P1500T1000!#003P1500T1000!#004P1500T1000!#005P1500T1000!}",
  123.     //直立
  124.     "{G0001#000P1500T1500!#001P1500T1500!#002P1500T1500!#003P1500T1500!#004P1500T1500!#005P1500T0000!}",
  125.     //蜷缩
  126.     "{G0002#000P1500T1500!#001P2200T1500!#002P2500T1500!#003P2000T1500!#004P1500T1500!#005P1500T1500!}",
  127.     //大前抓右放 K0001(3-11)
  128.     "{G0003#000P1500T1000!#001P1500T1000!#002P1500T1000!#003P1500T1000!#004P1500T1000!#005P1000T1000!}",
  129.     "{G0004#000P1500T1000!#001P1100T1000!#002P1600T1000!#003P2100T1000!#004P1500T1000!#005P1000T0000!}",
  130.     "{G0005#000P1500T1500!#001P1050T1500!#002P1600T1000!#003P2100T1000!#004P1500T1000!#005P2000T0000!}",
  131.     "{G0006#000P1500T1000!#001P1800T1000!#002P1800T1000!#003P2100T1000!#004P1500T1000!#005P2000T0000!}",
  132.     "{G0007#000P0800T1000!#001P1500T1000!#002P1500T1000!#003P2100T1000!#004P1500T1000!#005P2000T0000!}",
  133.     "{G0008#000P0800T1000!#001P1300T1000!#002P1800T1000!#003P2100T1000!#004P1500T1000!#005P2000T0000!}",
  134.     "{G0009#000P0800T1000!#001P1300T1000!#002P1800T1000!#003P2100T1000!#004P1500T1000!#005P1000T0000!}",
  135.     "{G0010#000P0800T1000!#001P1600T1000!#002P1800T1000!#003P2100T1000!#004P1500T1000!#005P1000T0000!}",
  136.     "{G0011#000P1500T1500!#001P2200T1500!#002P2500T1500!#003P2000T1500!#004P1500T1500!#005P1500T1500!}",
  137.     //前爪前放 K0002(12-18)
  138.     "{G0012#000P1500T1000!#001P1500T1000!#002P1500T1000!#003P1500T1000!#004P1500T1000!#005P1500T1000!}",
  139.     "{G0013#000P1520T1000!#001P1100T2000!#002P1850T1000!#003P2100T1000!#004P1500T1000!#005P1000T0000!}",
  140.     "{G0014#000P1520T1000!#001P1100T2000!#002P1900T1000!#003P2100T1000!#004P1500T1000!#005P2000T0000!}",
  141.     "{G0015#000P1520T1000!#001P1800T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P2000T1000!}",
  142.     "{G0016#000P1520T1000!#001P1100T2000!#002P1800T1000!#003P2000T1000!#004P1500T1000!#005P2000T1000!}",
  143.     "{G0017#000P1520T1000!#001P1100T2000!#002P1800T1000!#003P2000T1000!#004P1500T1000!#005P1000T0000!}",
  144.     "{G0018#000P1500T1500!#001P2200T1500!#002P2500T1500!#003P2000T1500!#004P1500T1500!#005P1500T1500!}",
  145.     //前爪左放 K0003(19-27)
  146.     "{G0019#000P1500T1000!#001P1500T1000!#002P1500T1000!#003P1500T1000!#004P1500T1000!#005P1500T1000!}",
  147.     "{G0020#000P1520T1000!#001P1100T2000!#002P1850T1000!#003P2100T1000!#004P1500T1000!#005P1000T0000!}",
  148.     "{G0021#000P1520T1000!#001P1100T2000!#002P1900T1000!#003P2100T1000!#004P1500T1000!#005P2000T0000!}",
  149.     "{G0022#000P1520T1000!#001P1800T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P2000T1000!}",
  150.     "{G0023#000P2200T1000!#001P1800T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P2000T1000!}",
  151.     "{G0024#000P2200T1000!#001P1200T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P2000T1000!}",
  152.     "{G0025#000P2200T1000!#001P1200T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P1000T0000!}",
  153.     "{G0026#000P2200T1000!#001P1800T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P1000T1000!}",
  154.     "{G0027#000P1500T1500!#001P2200T1500!#002P2500T1500!#003P2000T1500!#004P1500T1500!#005P1500T1500!}",
  155.     //前爪右放 K0004(28-36)
  156.     "{G0028#000P1500T1000!#001P1500T1000!#002P1500T1000!#003P1500T1000!#004P1500T1000!#005P1500T1000!}",
  157.     "{G0029#000P1520T1000!#001P1100T2000!#002P1850T1000!#003P2100T1000!#004P1500T1000!#005P1000T0000!}",
  158.     "{G0030#000P1520T1000!#001P1100T2000!#002P1900T1000!#003P2100T1000!#004P1500T1000!#005P2000T0000!}",
  159.     "{G0031#000P1520T1000!#001P1800T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P2000T1000!}",
  160.     "{G0032#000P0800T1000!#001P1800T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P2000T1000!}",
  161.     "{G0033#000P0800T1000!#001P1200T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P2000T1000!}",
  162.     "{G0034#000P0800T1000!#001P1200T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P1000T0000!}",
  163.     "{G0035#000P0800T1000!#001P1800T2000!#002P2000T1000!#003P2000T1000!#004P1500T1000!#005P1000T1000!}",
  164.     "{G0036#000P1500T1500!#001P2200T1500!#002P2500T1500!#003P2000T1500!#004P1500T1500!#005P1500T1500!}",
  165. };

  166. /*
  167.         代码从main里开始执行
  168.         在进入大循环while(1)之前都为各个模块的初始化
  169.         最后在大循环处理持续执行的事情
  170.         另外注意uart中的串口中断,接收数据处理
  171.         timer中的定时器中断,舵机的脉冲收发就在那里
  172. */

  173. void main(void) {
  174.         setup_global();                        //初始化全局变量
  175.         setup_gpio();                          //初始化IO口
  176.         setup_nled();                          //初始化工作指示灯
  177.         setup_beep();                          //初始化定时器
  178.         setup_djio();                          //初始化舵机IO口
  179.         setup_sensor();                        //初始化传感器IO口
  180.         setup_w25q64();                        //初始化存储器W25Q64
  181.         setup_ps2();                          //初始化PS2手柄
  182.         setup_vol();                          //初始化电压采集
  183.         setup_car_pwm();                //初始化电机PWM定时
  184.         setup_uart1();                        //初始化串口1
  185.         setup_uart2();                        //初始化串口2
  186.         setup_uart4();                        //初始化串口4
  187.         setup_systick();                //初始化滴答时钟,1S增加一次systick_ms的值
  188.         setup_others();                        //初始化其他
  189.         
  190.         setup_dj_timer();                //初始化定时器2 处理舵机PWM输出
  191.         setup_interrupt();        //初始化总中断
  192.         
  193.         setup_start();                        //初始化启动信号
  194.     while (1) {
  195.                 loop_nled();                              //循环执行工作指示灯,500ms跳动一次
  196.                 loop_uart();                              //串口数据接收处理
  197.                 loop_action();                            //动作组批量执行
  198.                 loop_bt_once();                            //蓝牙修改波特率和名称
  199.                 loop_ps2_data();                    //循环读取PS2手柄数据
  200.                 loop_ps2_button();                  //处理手柄上的按钮
  201.                 loop_ps2_car_pwm();                  //处理小车电机摇杆控制
  202.                 loop_save_something();  //定时保存一些变量
  203. //    loop_smart_sensor();          //处理智能传感器功能
  204.                 smart_xunji();                                  //循迹模式
  205. //                smart_soundjiaqu();                  //声控夹取
  206. //                smart_ziyoubizhang();                //自由避障
  207. //                smart_yssbjiaqu();                        //颜色识别
  208. //                smart_csbjiaqu();                          //定距夹取
  209. //                smart_gensui();                                  //跟随功能
  210. //                smart_xunjibizhang();                //循迹避障
  211. //                smart_xunjiyanse();                        //循迹识别
  212. //                smart_xunjicsbjiaqu();        //循迹定距
  213.                 }
  214. }

  215. //--------------------------------------------------------------------------------
  216. /*
  217.         初始化函数实现
  218. */
  219. //初始化全局变量
  220. void setup_global(void) {
  221.         //全局变量初始化
  222.         global_init();
  223. }
  224. //初始化IO口
  225. void setup_gpio(void) {
  226.         //IO初始化
  227.         io_init();
  228. }
  229. //初始化工作指示灯 初始化已在io_init中初始化
  230. void setup_nled(void) {
  231.         nled_off();                        //工作指示灯关闭
  232. }
  233. //初始化蜂鸣器 初始化已在io_init中初始化
  234. void setup_beep(void) {
  235.         beep_off();                        //关闭蜂鸣器
  236. }                        
  237. //初始化舵机IO口
  238. void setup_djio(void) {
  239.         dj_io_init();                //舵机IO口初始化
  240. }        

  241. void setup_vol(void) {
  242.         adc_init(ADC_VOL);
  243. }

  244. //初始化存储器W25Q64
  245. void setup_w25q64(void) {
  246. //存储器初始化,读取ID进行校验,若错误则长鸣不往下执行
  247.         w25x_init();
  248.         while(w25x_readId()!= W25Q64)beep_on();
  249.         
  250.         w25x_read((u8 *)(&eeprom_info), W25Q64_INFO_ADDR_SAVE_STR, sizeof(eeprom_info_t));        //读取全局变量
  251.         if(eeprom_info.version != VERSION) {        //判断版本是否是当前版本
  252.                 eeprom_info.version = VERSION;                  //复制当前版本
  253.                 eeprom_info.dj_record_num = 0;                  //学习动作组变量赋值0
  254.                 rewrite_eeprom();                                                  //写入到存储器
  255.         }
  256.         
  257.         if(eeprom_info.dj_bias_pwm[DJ_NUM] != FLAG_VERIFY) {
  258.                 for(i=0;i<DJ_NUM;i++) {
  259.                         eeprom_info.dj_bias_pwm[i] = 0;
  260.                 }
  261.                 eeprom_info.dj_bias_pwm[DJ_NUM] = FLAG_VERIFY;
  262.         }
  263.         
  264.         
  265. }        

  266. //初始化PS2手柄
  267. void setup_ps2(void) {
  268.         //手柄初始化
  269.         psx_init();
  270. }
  271. //初始化定时器2 处理舵机PWM输出
  272. void setup_dj_timer(void) {
  273.         timer1_init();        //舵机 定时器初始化
  274. }
  275. //初始化电机PWM定时
  276. void setup_car_pwm(void) {
  277.         //小车 pwm 初始化
  278.         pwm_init(CYCLE);
  279.         car_pwm_set(0,0);        //设置小车的左右轮速度为0
  280. }        
  281. //初始化串口1
  282. void setup_uart1(void) {
  283.         //串口1初始化
  284.         uart1_init(115200);
  285.         //uart1_close();
  286.         uart1_open();
  287.         //串口发送测试字符
  288.         uart1_send_str((u8 *)"uart1 check ok!");
  289. }
  290. //初始化串口2
  291. void setup_uart2(void) {
  292.         //串口2初始化
  293.         uart2_init(115200);
  294.         //uart2_close();
  295.         uart2_open();
  296.         //串口发送测试字符
  297.         uart2_send_str((u8 *)"uart2 check ok!");
  298. }        
  299. //初始化串口4
  300. void setup_uart4(void) {
  301.         //串口4初始化
  302.         uart4_init(115200);
  303.         //uart4_close();
  304.         uart4_open();
  305.         
  306.         //串口发送测试字符
  307.         uart4_send_str((u8 *)"uart4 check ok!");
  308. }        
  309. //初始化滴答时钟,1S增加一次systick_ms的值
  310. void setup_systick(void) {
  311.         //系统滴答时钟初始化        
  312.         timer0_init();
  313. }        


  314. //初始化启动信号
  315. void setup_start(void) {
  316.         //蜂鸣器LED 名叫闪烁 示意系统启动
  317.         beep_on();nled_on();mdelay(100);beep_off();nled_off();mdelay(100);
  318.         beep_on();nled_on();mdelay(100);beep_off();nled_off();mdelay(100);
  319.         beep_on();nled_on();mdelay(100);beep_off();nled_off();mdelay(100);
  320. }        
  321. //初始化其他
  322. void setup_others(void) {        
  323.         //机械臂蜷缩 G0002组
  324.         memset(uart_receive_buf, 0, sizeof(uart_receive_buf));
  325.         if(ACTION_USE_ROM) {
  326.                 //使用存储在单片机内部rom中的动作组
  327.                 strcpy((char *)uart_receive_buf, action_pre_group[2]);
  328.         } else {
  329.                 //从存储芯片中读取第group_num个动作组
  330.                 w25x_read(uart_receive_buf, 2*ACTION_SIZE, ACTION_SIZE);        
  331.         }
  332.         //把读取出来的动作组传递到do_action执行
  333.         for(i=16;i<strlen((char *)uart_receive_buf);i+=15) {
  334.                 uart_receive_buf[i] = '0';
  335.                 uart_receive_buf[i+1] = '0';
  336.                 uart_receive_buf[i+2] = '0';
  337.                 uart_receive_buf[i+3] = '0';
  338.         }
  339.         do_action(uart_receive_buf);
  340.         //执行预存命令 {G0000#000P1500T1000!#000P1500T1000!}
  341.         if(eeprom_info.pre_cmd[PRE_CMD_SIZE] == FLAG_VERIFY) {
  342.                 strcpy((char *)uart_receive_buf, (char *)eeprom_info.pre_cmd);
  343.                 if(eeprom_info.pre_cmd[0] == '


  344. ) {
  345.                         parse_cmd(eeprom_info.pre_cmd);
  346.                 } else {
  347.                         for(i=16;i<strlen((char *)uart_receive_buf);i+=15) {
  348.                                 uart_receive_buf[i] = '0';
  349.                                 uart_receive_buf[i+1] = '0';
  350.                                 uart_receive_buf[i+2] = '0';
  351.                                 uart_receive_buf[i+3] = '0';
  352.                         }
  353.                         do_action(uart_receive_buf);
  354.                 }
  355.         }
  356.         
  357. }

  358. //初始化总中断
  359. void setup_interrupt(void) {
  360.         //串口1设为高优先级
  361.         IP = 0X10;
  362.         //IP2 = 0X01;
  363.         //总中断打开
  364.         EA = 1;
  365. }        
  366. //--------------------------------------------------------------------------------


  367. //--------------------------------------------------------------------------------
  368. /*
  369.         主循环函数实现
  370. */
  371. //循环执行工作指示灯,500ms跳动一次
  372. void loop_nled(void) {
  373.         static u32 systick_ms_bak = 0;
  374.         if(millis() - systick_ms_bak >= 500) {
  375.                 systick_ms_bak = millis();
  376.                 nled_switch();        
  377.         }
  378. }               
  379. //串口数据接收处理
  380. void loop_uart(void) {
  381.         static u8 do_once1 = 0, do_once2 = 0;
  382.         if(uart1_get_ok) {
  383.                 //测试发回去
  384.                 //uart1_send_str(uart_receive_buf);
  385.                 if(uart1_mode == 1) {                                //命令模式
  386.                         //uart1_send_str(">cmd");
  387.                         parse_cmd(uart_receive_buf);                        
  388.                 } else if(uart1_mode == 2) {                //单个舵机模式
  389.                         //uart1_send_str(">sig");
  390.                         do_action(uart_receive_buf);
  391.                 } else if(uart1_mode == 3) {                //多个舵机模式
  392.                         //uart1_send_str(">group:");
  393.                         do_action(uart_receive_buf);
  394.                 } else if(uart1_mode == 4) {                //保存模式
  395.                         //uart1_send_str(">save");
  396.                         //uart1_send_str(uart_receive_buf);
  397.                         action_save(uart_receive_buf);
  398.                 }
  399.                 uart1_mode = 0;
  400.                 uart1_get_ok = 0;
  401.                 //uart1_open();
  402.         }
  403.         

  404.         if(millis() - get_uart_timeout() > 100) {
  405.                 if(!do_once1) {
  406.                         timer1_open();
  407.                         do_once1 = 1;
  408.                         do_once2 = 0;
  409.                 }
  410.         } else {
  411.                 if(!do_once2) {
  412.                         timer1_close();
  413.                         do_once1 = 0;
  414.                         do_once2 = 1;
  415.                 }
  416.         }
  417.         
  418.         return;
  419. }        

  420. //定时保存一些变量
  421. void loop_save_something(void) {
  422.         static u32 saveTime = 3000;
  423.         if((djBiasSaveFlag == 1) && (millis() - bias_systick_ms_bak > saveTime)) {
  424.                 djBiasSaveFlag = 0;
  425.                 bias_systick_ms_bak = millis();
  426.                 rewrite_eeprom();
  427.         }        
  428.         return;
  429. }        


  430. void loop_ps2_data(void) {
  431.         static u32 systick_ms_bak = 0;
  432.         if(millis() - systick_ms_bak < 20) {
  433.                 return;
  434.         }
  435.         systick_ms_bak = millis();
  436.         psx_write_read(psx_buf);
  437. //#if 0        
  438. //        sprintf(cmd_return, "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\r\n",
  439. //        (int)psx_buf[0], (int)psx_buf[1], (int)psx_buf[2], (int)psx_buf[3],
  440. //        (int)psx_buf[4], (int)psx_buf[5], (int)psx_buf[6], (int)psx_buf[7], (int)psx_buf[8]);
  441. //        uart1_send_str(cmd_return);
  442. //#endif         
  443.         return;
  444. }
  445. //处理遥感数据,控制电机
  446. void loop_ps2_car_pwm(void) {
  447.         static int car_left_bak=0, car_right_bak=0;
  448.         int car_left, car_right;
  449.         
  450.         if(psx_buf[1] != PS2_LED_RED)return;
  451.         car_left = (127 - psx_buf[8]) * 8;
  452.         car_right = (127 - psx_buf[6]) * 8;
  453.         
  454.         if(car_left != car_left_bak || car_right != car_right_bak) {
  455.                 car_pwm_set(car_left, car_right);
  456.                 car_left_bak = car_left;
  457.                 car_right_bak = car_right;
  458.         }

  459. }


  460. //接收手柄按键数据
  461. void loop_ps2_button(void) {
  462.         static unsigned char psx_button_bak[2] = {0};
  463.         static unsigned char mode_bak;

  464.         //处理智能模式 红灯模式下 智能模式取消,此时为遥控模式
  465.         if(mode_bak != psx_buf[1]) {
  466.                 mode_bak = psx_buf[1];
  467.                 if(PS2_LED_RED == psx_buf[1]) {
  468.                         smart_mode = 255;
  469.                 }
  470.                 car_pwm_set(0,0);
  471.                 group_do_ok = 1;
  472.                 //beep_on_times(1, 500);
  473.         }

  474.         if((psx_button_bak[0] == psx_buf[3])
  475.         && (psx_button_bak[1] == psx_buf[4])) {                        
  476.         } else {
  477.                 parse_psx_buf(psx_buf+3, psx_buf[1]);
  478.                 psx_button_bak[0] = psx_buf[3];
  479.                 psx_button_bak[1] = psx_buf[4];
  480.         }
  481.         return;
  482. }

  483. //处理手柄接收到的数据
  484. void parse_psx_buf(unsigned char *buf, unsigned char mode) {
  485.         u8 i, pos = 0;
  486.         static u16 bak=0xffff, temp, temp2;
  487.         temp = (buf[0]<<8) + buf[1];
  488.         
  489.         if(bak != temp) {
  490.                 temp2 = temp;
  491.                 temp &= bak;
  492.                 for(i=0;i<16;i++) {
  493.                         if((1<<i) & temp) {
  494.                         } else {
  495.                                 if((1<<i) & bak) {        //press
  496.                                                                                                                         
  497.                                         memset(uart_receive_buf, 0, sizeof(uart_receive_buf));                                       
  498.                                         if(mode == PS2_LED_RED) {
  499.                                                 memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_red[i], strlen(pre_cmd_set_red[i]));
  500.                                         } else if(mode == PS2_LED_GRN) {
  501.                                                 memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_grn[i], strlen(pre_cmd_set_grn[i]));
  502.                                         } else continue;
  503.                                        
  504.                                         pos = str_contain_str(uart_receive_buf, "^");
  505.                                         if(pos) uart_receive_buf[pos-1] = '\0';
  506.                                         if(str_contain_str(uart_receive_buf, "[        DISCUZ_CODE_0        ]quot;)) {
  507.                                                 //uart1_close();
  508.                                                 //uart1_get_ok = 1;
  509.                                                 //uart1_mode = 1;
  510.                                                 strcpy(cmd_return, uart_receive_buf+11);
  511.                                                 strcpy(uart_receive_buf, cmd_return);
  512.                                                 parse_cmd(uart_receive_buf);
  513.                                         } else if(str_contain_str(uart_receive_buf, "#")) {
  514.                                                 //uart1_close();
  515.                                                 //uart1_get_ok = 1;
  516.                                                 //uart1_mode = 2;
  517.                                                 strcpy(cmd_return, uart_receive_buf+11);
  518.                                                 strcpy(uart_receive_buf, cmd_return);
  519.                                                 do_action(uart_receive_buf);
  520.                                         }
  521.                                        
  522.                                         //uart1_send_str(uart_receive_buf);
  523.                                         //zx_uart_send_str(uart_receive_buf);
  524.                                        
  525.                                         bak = 0xffff;
  526.                                 } else {//release
  527.                                                                                 
  528.                                         memset(uart_receive_buf, 0, sizeof(uart_receive_buf));                                       
  529.                                         if(mode == PS2_LED_RED) {
  530.                                                 memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_red[i], strlen(pre_cmd_set_red[i]));
  531.                                         } else if(mode == PS2_LED_GRN) {
  532.                                                 memcpy((char *)uart_receive_buf, (char *)pre_cmd_set_grn[i], strlen(pre_cmd_set_grn[i]));
  533.                                         } else continue;        
  534.                                        
  535.                                         pos = str_contain_str(uart_receive_buf, "^");
  536.                                         if(pos) {
  537.                                                 if(str_contain_str(uart_receive_buf+pos, "[        DISCUZ_CODE_0        ]quot;)) {
  538.                                                         //uart1_close();
  539.                                                         //uart1_get_ok = 1;
  540.                                                         //uart1_mode = 1;
  541.                                                         strcpy(cmd_return, uart_receive_buf+pos);
  542.                                                         cmd_return[strlen(cmd_return) - 1] = '\0';
  543.                                                         strcpy(uart_receive_buf, cmd_return);
  544.                                                         parse_cmd(uart_receive_buf);
  545.                                                 } else if(str_contain_str(uart_receive_buf+pos, "#")) {
  546.                                                         //uart1_close();
  547.                                                         //uart1_get_ok = 1;
  548.                                                         //uart1_mode = 2;
  549.                                                         strcpy(cmd_return, uart_receive_buf+pos);
  550.                                                         cmd_return[strlen(cmd_return) - 1] = '\0';
  551.                                                         strcpy(uart_receive_buf, cmd_return);
  552.                                                         do_action(uart_receive_buf);
  553.                                                 }
  554.                                                 //uart1_send_str(uart_receive_buf);
  555.                                                 //zx_uart_send_str(uart_receive_buf);
  556.                                         }        
  557.                                 }
  558.                                 //测试执行指令
  559.                                 //uart1_send_str(uart_receive_buf);

  560.                         }
  561.                 }
  562.                 bak = temp2;
  563.                 beep_on();mdelay(50);beep_off();
  564.         }        
  565.         return;
  566. }

  567. //void handle_uart(void) {

  568. //        return;
  569. //}

  570. /*
  571. parse_cmd( )的作用是解析下列指令
  572.         $DST!
  573.         $DST:x!
  574.         $RST!
  575.         $CGP:%d-%d!
  576.         $DEG:%d-%d!
  577.         $DGS:x!
  578.         $DGT:%d-%d,%d!
  579.         $DCR:%d,%d!
  580.         $DWA!
  581.         $DWD!
  582.         $DJR!
  583.         $GETA!
  584. */
  585. void parse_cmd(u8 *cmd) {
  586.         //u32 uint1;
  587.         static u8 djrFlag=0;
  588.         u16 pos, i, index;
  589.         int int1, int2;
  590.         
  591.         uart1_send_str(cmd);
  592.         
  593.         if(pos = str_contain_str(cmd, "$DST!"), pos) {
  594.                 dbt_flag = 0;
  595.                 group_do_ok  = 1;
  596.                 for(i=0;i<DJ_NUM;i++) {
  597.                         duoji_doing[i].inc = 0;        
  598.                         duoji_doing[i].aim = duoji_doing[i].cur;
  599.                 }
  600.                 zx_uart_send_str("#255PDST!");
  601.         } else if(pos = str_contain_str(cmd, "$DST:"), pos) {
  602.                 if(sscanf(cmd, "$DST:%d!", &index)) {
  603.                         duoji_doing[index].inc = 0;        
  604.                         duoji_doing[index].aim = duoji_doing[index].cur;
  605.                         sprintf(cmd_return, "#%03dPDST!", (int)index);
  606.                         zx_uart_send_str(cmd_return);
  607.                 }
  608.                
  609.                
  610.         } else if(pos = str_contain_str(cmd, "$RST!"), pos) {               
  611.                 soft_reset();
  612.         } else if(pos = str_contain_str(cmd, "$CGP:"), pos) {               
  613.                 if(sscanf(cmd, "$CGP:%d-%d!", &int1, &int2)) {
  614.                         print_group(int1, int2);
  615.                 }
  616.         } else if(pos = str_contain_str(cmd, "$DEG:"), pos) {               
  617.                 if(sscanf(cmd, "$DEG:%d-%d!", &int1, &int2)) {
  618.                         erase_sector(int1, int2);
  619.                 }
  620.         } else if(pos = str_contain_str(cmd, "$DGS:"), pos) {               
  621.                 if(sscanf(cmd, "$DGS:%d!", &int1)) {
  622.                         do_group_once(int1);
  623.                         group_do_ok = 1;
  624.                 }
  625.         } else if(pos = str_contain_str(cmd, "$DGT:"), pos) {               
  626.                 if(sscanf((char *)cmd, "$DGT:%d-%d,%d!", &group_num_start, &group_num_end, &group_num_times)) {
  627.                         //uart1_send_str("111111");                        
  628.                         if(group_num_start != group_num_end) {
  629.                                 do_start_index = group_num_start;
  630.                                 do_time = group_num_times;
  631.                                 group_do_ok = 0;
  632.                                 //uart1_send_str("22222");
  633.                         } else {
  634.                                 group_do_ok = 1;
  635.                                 do_group_once(group_num_start);
  636.                                 //uart1_send_str("33333");
  637.                         }
  638.                 }
  639.         } else if(pos = str_contain_str(cmd, "$DCR:"), pos) {               
  640.                 if(sscanf(cmd, "$DCR:%d,%d!", &int1, &int2)) {
  641.                         car_pwm_set(int1, int2);
  642.                 }
  643.         } else if(pos = str_contain_str(cmd, "$DWA!"), pos) {               
  644.                 car_dw--;
  645.                 if(car_dw == 0)car_dw = 1;
  646.                 beep_on();mdelay(100);beep_off();
  647.         } else if(pos = str_contain_str(cmd, "$DWD!"), pos) {               
  648.                 car_dw++;
  649.                 if(car_dw == 4)car_dw = 3;
  650.                 beep_on();mdelay(100);beep_off();
  651.         } else if(pos = str_contain_str(cmd, "$CAR_FARWARD!"), pos) {               
  652.                 car_pwm_set(1000, 1000);
  653.         } else if(pos = str_contain_str(cmd, "$CAR_BACKWARD!"), pos) {               
  654.                 car_pwm_set(-1000, -1000);
  655.         } else if(pos = str_contain_str(cmd, "$CAR_LEFT!"), pos) {               
  656.                 car_pwm_set(-1000, 1000);
  657.         } else if(pos = str_contain_str(cmd, "$CAR_RIGHT!"), pos) {               
  658.                 car_pwm_set(1000, -1000);
  659.         } else if(pos = str_contain_str(cmd, "$DJR!"), pos) {        
  660.                 zx_uart_send_str("#255P1500T2000!");               
  661.                 for(i=0;i<DJ_NUM;i++) {
  662.                         duoji_doing[i].aim  = 1500;
  663.                         duoji_doing[i].time = 2000;
  664.                         duoji_doing[i].inc = (duoji_doing[i].aim -  duoji_doing[i].cur) / (duoji_doing[i].time/20.000);
  665.                 }
  666.                
  667.                 if(djrFlag) {
  668.                         do_group_once(1);
  669.                 } else {
  670.                         do_group_once(2);
  671.                 }
  672.                 djrFlag = !djrFlag;
  673.         } else if(pos = str_contain_str(cmd, "$GETA!"), pos) {               
  674.                 uart1_send_str("AAA");
  675.         } else if(pos = str_contain_str(cmd, "$GETS!"), pos) {               
  676.                 if(group_do_ok == 0) {
  677.                         uart1_send_str("group_do_ok=0");
  678.                 } else {
  679.                         uart1_send_str("group_do_ok=1");
  680.                 }
  681.         } else if(pos = str_contain_str(cmd, "$GETINC!"), pos) {               
  682.                 for(i=0;i<8;i++) {
  683.                         sprintf(cmd_return, "inc%d = %f \r\n", (int)i, duoji_doing[i].inc);
  684.                         uart1_send_str(cmd_return);
  685.                 }
  686.         }else if(pos = str_contain_str(uart_receive_buf, "$DBT:"), pos) {               
  687.                 if(sscanf(uart_receive_buf, "$DBT:%d,%d!", &int1, &int2)) {
  688.                         if(int1 == 1) {
  689.                                 group_num_start = 1;
  690.                                 group_num_end = 10;
  691.                                 group_num_times = int2;
  692.                         } else if(int1 == 2) {
  693.                                 group_num_start = 11;
  694.                                 group_num_end = 20;
  695.                                 group_num_times = int2;
  696.                         } else if(int1 == 3) {
  697.                                 group_num_start = 21;
  698.                                 group_num_end = 30;
  699.                                 group_num_times = int2;
  700.                         } else if(int1 == 4) {
  701.                                 group_num_start = 31;
  702.                                 group_num_end = 40;
  703.                                 group_num_times = int2;
  704.                         } else {
  705.                                 group_num_start = 0;
  706.                                 group_num_end = 0;
  707.                         }
  708.                         
  709.                         if(group_num_start != group_num_end) {
  710.                                 do_start_index = group_num_start;
  711.                                 do_time = group_num_times;
  712.                                 group_do_ok = 0;
  713.                                 dbt_flag = 1;
  714.                         } else {
  715.                                 do_group_once(group_num_start);
  716.                         }
  717.                         
  718.                 }
  719.         } else if(pos = str_contain_str(cmd, "$DRS!"), pos) {        
  720.                 uart1_send_str("51MCU-IAP15W4K61S4");
  721.         } else if(pos = str_contain_str(cmd, (u8 *)"$SMODE"), pos) {               
  722.                 if(sscanf((char *)cmd, "$SMODE%d!", &int1)) {
  723.                         if(int1 < 10) {
  724.                                 smart_mode = int1;
  725.                                 beep_on_times(1, 100);
  726.                                 car_pwm_set(0,0);
  727.                                 //uart1_send_str(cmd);
  728.                         }
  729.                 }
  730.         }
  731. }


  732. //预存指令处理
  733. void action_save(u8 *str) {
  734.         int action_index = 0;
  735.         //预存命令处理
  736.         if(str[1] == '

  737. && str[2] == '!') {
  738.                 eeprom_info.pre_cmd[PRE_CMD_SIZE] = 0;
  739.                 rewrite_eeprom();
  740.                 uart1_send_str((u8 *)"@CLEAR PRE_CMD OK!");
  741.                 return;
  742.         } else if(str[1] == '


  743. ) {
  744.                 if(sscanf((char *)str, "<$DGT:%d-%d,%d!>", &group_num_start, &group_num_end, &group_num_times)) {
  745.                         if(group_num_start == group_num_end) {
  746.                                 w25x_read(eeprom_info.pre_cmd, group_num_start*ACTION_SIZE, ACTION_SIZE);        
  747.                         } else {
  748.                                 memset(eeprom_info.pre_cmd, 0, sizeof(eeprom_info.pre_cmd));
  749.                                 strcpy((char *)eeprom_info.pre_cmd, (char *)str+1);
  750.                                 eeprom_info.pre_cmd[strlen((char *)str) - 2] = '\0';
  751.                         }
  752.                         eeprom_info.pre_cmd[PRE_CMD_SIZE] = FLAG_VERIFY;
  753.                         rewrite_eeprom();
  754.                         //uart1_send_str(eeprom_info.pre_cmd);
  755.                         uart1_send_str((u8 *)"@SET PRE_CMD OK!");
  756.                 }
  757.                 return;
  758.         }
  759.         
  760.         action_index = get_action_index(str);
  761.         //<G0001#001...>
  762.         if((action_index == -1) || str[6] != '#'){
  763.         //if( action_index == -1 ){
  764.                 uart1_send_str("E");
  765.                 return;
  766.         }
  767.         //save_action_index_bak++;
  768.         if(action_index*ACTION_SIZE % W25Q64_SECTOR_SIZE == 0)w25x_erase_sector(action_index*ACTION_SIZE/W25Q64_SECTOR_SIZE);
  769.         replace_char(str, '<', '{');
  770.         replace_char(str, '>', '}');
  771.         w25x_write(str, action_index*ACTION_SIZE, strlen(str) + 1);
  772.         //uart1_send_str(str);
  773.         uart1_send_str("A");
  774.         return;        
  775. }
  776. //获取指令中舵机ID号
  777. int get_action_index(u8 *str) {
  778.         int index = 0;
  779.         //uart_send_str(str);
  780.         while(*str) {
  781.                 if(*str == 'G') {
  782.                         str++;
  783.                         while((*str != '#') && (*str != '


  784. )) {
  785.                                 index = index*10 + *str-'0';
  786.                                 str++;        
  787.                         }
  788.                         return index;
  789.                 } else {
  790.                         str++;
  791.                 }
  792.         }
  793.         return -1;
  794. }
  795. //打印动作组到串口
  796. void print_group(int start, int end) {
  797.         if(start > end) {
  798.                 int_exchange(&start, &end);
  799.         }
  800.         for(;start<=end;start++) {
  801.                 memset(uart_receive_buf, 0, sizeof(uart_receive_buf));
  802.                 w25x_read(uart_receive_buf, start*ACTION_SIZE, ACTION_SIZE);
  803.                 uart1_send_str(uart_receive_buf);
  804.                 uart1_send_str("\r\n");
  805.         }
  806. }

  807. //交换两个变量
  808. void int_exchange(int *int1, int *int2) {
  809.         int int_temp;
  810.         int_temp = *int1;
  811.         *int1 = *int2;
  812.         *int2 = int_temp;
  813. }

  814. //擦除相应扇区
  815. void erase_sector(int start, int end) {
  816.         if(start > end) {
  817.                 int_exchange(&start, &end);
  818.         }
  819.         if(end >= 127)end = 127;
  820.         for(;start<=end;start++) {
  821.                 SpiFlashEraseSector(start);
  822.                 sprintf(cmd_return, "@Erase %d OK!", start);
  823.                 uart1_send_str(cmd_return);
  824.         }
  825.         save_action_index_bak = 0;
  826. }


  827. //执行动作一次
  828. void do_group_once(int group_num) {
  829.         memset(uart_receive_buf, 0, sizeof(uart_receive_buf));
  830.         if(ACTION_USE_ROM) {
  831.                 //使用存储在单片机内部rom中的动作组
  832.                 strcpy((char *)uart_receive_buf, action_pre_group[group_num]);
  833.         } else {
  834.                 //从存储芯片中读取第group_num个动作组
  835.                 w25x_read(uart_receive_buf, group_num*ACTION_SIZE, ACTION_SIZE);        
  836.         }
  837.         //把读取出来的动作组传递到do_action执行
  838.         do_action(uart_receive_buf);
  839.         sprintf((char *)cmd_return, "@DoGroup %d OK!\r\n", group_num);
  840.         uart1_send_str(cmd_return);
  841. }
  842. //取绝对值
  843. float abs_float(float value) {
  844.         if(value>0) {
  845.                 return value;
  846.         }
  847.         return (-value);
  848. }

  849. //舵机增量处理
  850. void duoji_inc_handle(u8 index) {        
  851.         int aim_temp;
  852.         
  853.         if(duoji_doing[index].inc != 0) {
  854.                
  855.                 aim_temp = duoji_doing[index].aim;
  856.                
  857.                 if(aim_temp > 2500){
  858.                         aim_temp = 2500;
  859.                 } else if(aim_temp < 500) {
  860.                         aim_temp = 500;
  861.                 }
  862.         
  863.                 if(abs_float(aim_temp - duoji_doing[index].cur) <= abs_float(duoji_doing[index].inc + duoji_doing[index].inc)) {
  864.                         duoji_doing[index].cur = aim_temp;
  865.                         duoji_doing[index].inc = 0;
  866.                 } else {
  867.                         duoji_doing[index].cur += duoji_doing[index].inc;
  868.                 }
  869.         }
  870. }

  871. //动作组批量执行
  872. void loop_action(void) {
  873.         
  874.         if(timer1_flag_dj) {
  875.                 duoji_inc_handle(duoji_index1);
  876.                 timer1_flag_dj = 0;
  877.         }
  878.         
  879.         if((check_dj_state() == 0) && (group_do_ok == 0)) {
  880.                 do_group_once(do_start_index);
  881.                
  882.                 if(group_num_start<group_num_end) {
  883.                         if(do_start_index == group_num_end) {
  884.                                 do_start_index = group_num_start;
  885.                                 if(group_num_times != 0) {
  886.                                         do_time--;
  887.                                         if(do_time == 0) {
  888.                                                 group_do_ok = 1;
  889.                                                 uart1_send_str((u8*)"@GroupDone!");
  890.                                         }
  891.                                 }
  892.                                 return;
  893.                         }
  894.                         do_start_index++;
  895.                 } else {
  896.                         if(do_start_index == group_num_end) {
  897.                                 do_start_index = group_num_start;
  898.                                 if(group_num_times != 0) {
  899.                                         do_time--;
  900.                                         if(do_time == 0) {
  901.                                                 group_do_ok = 1;
  902.                                                 uart1_send_str((u8*)"@GroupDone!");
  903.                                         }
  904.                                 }
  905.                                 return;
  906.                         }
  907.                         do_start_index--;
  908.                 }
  909.         }
  910.         
  911. }

  912. //舵机状态处理,有舵机处理动作返回1,否则返回0
  913. u8 check_dj_state(void) {
  914.         int i;
  915.         for(i=0;i<DJ_NUM;i++) {
  916.                 if(duoji_doing[i].inc) return 1;
  917.         }
  918.         return 0;
  919. }
  920. //单个动作处理
  921. void do_action(u8 *uart_receive_buf) {
  922.         u16 index,  time,i, lst_i, parse_ok;
  923.         int bias;
  924.         float pwm;
  925.         float aim_temp;
  926.         zx_uart_send_str(uart_receive_buf);
  927.         zx_uart_send_str("\r\n");
  928.         
  929.         if(uart_receive_buf[0] == '#' && uart_receive_buf[4] == 'P' && uart_receive_buf[5] == 'S' && uart_receive_buf[6] == 'C' && uart_receive_buf[7] == 'K' && uart_receive_buf[12] == '!') {
  930.                 index = (uart_receive_buf[1] - '0')*100 + (uart_receive_buf[2] - '0')*10 + (uart_receive_buf[3] - '0');
  931.                 bias = (uart_receive_buf[9] - '0')*100 + (uart_receive_buf[10] - '0')*10 + (uart_receive_buf[11] - '0');
  932.                 if((bias >= -500) && (bias <= 500) && (index < DJ_NUM)) {
  933.                         if(uart_receive_buf[8] == '+') {
  934.                         } else if(uart_receive_buf[8] == '-') {
  935.                                 bias = -bias;
  936.                         }
  937.                         aim_temp = duoji_doing[index].cur + 0.043198 - eeprom_info.dj_bias_pwm[index] + bias;
  938.                         eeprom_info.dj_bias_pwm[index] = bias;                        
  939.                         if(aim_temp > 2497){
  940.                                 aim_temp = 2497;
  941.                         } else if(aim_temp < 500) {
  942.                                 aim_temp = 500;
  943.                         }
  944.                         
  945.                         duoji_doing[index].aim = aim_temp;
  946.                         duoji_doing[index].cur = aim_temp;
  947.                         duoji_doing[index].inc = 0;
  948.                         bias_systick_ms_bak = millis();
  949.                         djBiasSaveFlag = 1;
  950.                 }
  951.                 return;
  952.         }
  953.         
  954.                
  955.         i = 0;parse_ok = 0;
  956.         while(uart_receive_buf[i]) {
  957.                 if(uart_receive_buf[i] == '#') {
  958.                         lst_i = i;
  959.                         index = 0;i++;
  960.                         while(uart_receive_buf[i] && (uart_receive_buf[i] != 'P')) {
  961.                                 index = index*10 + uart_receive_buf[i]-'0';i++;
  962. ……………………

  963. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
01 循迹模式.rar (357.14 KB, 下载次数: 65)
回复

使用道具 举报

ID:1 发表于 2018-8-29 03:19 | 显示全部楼层
补全原理图与详细说明资料后即可获得100+黑币
回复

使用道具 举报

ID:704748 发表于 2020-3-8 20:02 | 显示全部楼层
请问楼主文中的eeprom_info.pre_cmd这个成员是什么意思呢?
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表