野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 3009|回复: 3

【瑞萨RA MCU创意氛围赛】瑞萨RA蓝牙平衡小车

[复制链接]
发表于 2023-7-5 17:51:20 | 显示全部楼层 |阅读模式
本帖最后由 克哈keha 于 2023-7-5 21:39 编辑
一、简介
1.平衡小车运行模式(通过蓝牙控制):(1)平衡模式(2)跟随模式(3)避障模式。   
2.手机控制小车前进后退转向加减速等。
3.小车拿起、放下检测(控制小车是否运行)
4.可通过Type-C数据线与上位机调试

5.预留NRF24L01、红外接口、多路电源接口可以拓展开发
6.后续待开发......

二、展示
平衡小车视频(后续更新全视频): 平衡小车运行模式.zip (8.17 MB, 下载次数: 160)
1688549398054.jpg
小车实物图

RA2小板2.jpg RA2小板1.jpg
RA2小板实物图

1687793145262.jpg 1687793175282.jpg
RA2小板

1687793348488.jpg 1687793413435.jpg
RA平衡小车底板



三、简介
瑞萨RA平衡小车系统框架如下图:
1688539932838.jpg
2串电池产生7.2V,输入到电源模块产生5V,再通过LDO产生3.3V。
平衡模式:通过MPU6050检测小车姿态,RA MCU控制电机驱动模块控制电机运行,并显示到OLED上。
跟随模式:小车通过超声波模块检测距离,在一定距离内开启跟踪。
避障模式:小车直行,通过超声波模块判断前方是否存在障碍物,若遇到障碍物将转弯。
蓝牙:手机通过与蓝牙模块链接,控制小车运行模式,并可对小车进行控制。

四、模块准备
由于开发板不易于与底板链接,所以自行制作了一块小板:
1688562536108.png
RA2小板原理图

平衡小车底板板载串口模块与LDO:
1688564305822.jpg 1688563841609.jpg
平衡小车底板串口模块

电源模块:LM2596S DC-DC降压电源模块

MPU6050模块:MPU-6050模块三轴加速度+三轴陀螺仪

OLED模块:0.96寸 OLED显示液晶屏模块(注意区分VCC与GND引脚顺序,下图不正确)

电机驱动模块:TB6612FNG电机驱动模块

蓝牙模块:蓝牙3.0模块 SPP透传 兼容HC-05/06从机 JDY-31

暂时先更新这些,后续更新......

回复

使用道具 举报

 楼主| 发表于 2023-8-21 23:45:40 | 显示全部楼层
放一边太久差点忘记了。。。


B站视频:https://www.bilibili.com/video/BV1x84y1Z7HQ/?spm_id_from=333.999.0.0&vd_source=e9a41e618602e99bc20cf9fbfd79c4c9


五、部分内容介绍
1111.jpg
通过蓝牙控制平衡小车模式,平衡模式下小车前进后退左转右转,加速减速停止,开机上电默认平衡模式。(1平衡模式 2跟踪模式 3避障模式)


平衡小车倒下检测:当小车倒下(到达一定角度),停止电机
1692631198297.jpg

平衡小车拿起检测:当小车被拿起来(轮子高速转动一定时间),停止电机
1692631323463.jpg


平衡小车放下检测:当小车重新被放下一定时间(轮子没有转动并且角度小于一定范围),重新进入平衡模式
1692631386758.jpg


PID控制:
  1. <div style="background-color: rgb(255, 255, 255); padding-left: 2px;">
  2. <div style="color: rgb(0, 0, 0); font-family: Consolas; font-size: 14pt; text-wrap: nowrap;">
  3. <p style="font-size: 18.6667px;"><span style="color: rgb(0, 80, 50);">_PID_CONTROL</span> vel = {130.0f, 0.65f, 0.0f};</p><p style="font-size: 18.6667px;"><span style="color: rgb(0, 80, 50);">_PID_CONTROL</span> bal = {300.0f, 0.0f , 20.0f};</p><p style="font-size: 18.6667px;"><span style="color: rgb(0, 80, 50);">_PID_CONTROL</span> tur = {5.0f, 0.0f, 10.0f}; </p><p style="font-size: 18.6667px;">
  4. </p><p style="font-size: 18.6667px;">
  5. </p><p><span style="background-color: rgb(247, 247, 247); color: rgb(68, 68, 68); font-family: Tahoma, &quot;Microsoft Yahei&quot;, Simsun; font-size: 14px;">/*</span></p></div></div>
复制代码


输出控制:
  1. /*
  2. * 描述  :控制两路PWM输出
  3. */
  4. uint32_t pwm_1=0,duty_1=0;
  5. uint32_t pwm_2=0,duty_2=0;
  6. void motor_pwm_out(uint16_t pwm1,uint16_t pwm2)
  7. {
  8.     pwm_1 = to_limit(pwm1,0,7199);
  9.     pwm_2 = to_limit(pwm2,0,7199);
  10.     R_GPT_DutyCycleSet(&g_pwm1_ctrl, pwm_1, GPT_IO_PIN_GTIOCA);
  11.     R_GPT_DutyCycleSet(&g_pwm2_ctrl, pwm_2, GPT_IO_PIN_GTIOCA);

  12. }
  13. /*
  14. * 描述  :控制输出
  15. */
  16. void _ctr_out(void)
  17. {
  18.                 uint8_t i;

  19.     if(PickUpTheCar(att.rol,hall1count,hall2count) == 1)   //小车被拿起检测
  20.     {
  21.         theCarStopFlag = 1;                                                                        //停止运行标志
  22.     }
  23.     if(PutDownTheCar(att.rol,hall1count,hall2count))       //小车被放下检测
  24.     {
  25.         theCarStopFlag = 0;                                                                        //运行标志
  26.     }

  27.     /* 检测是否停止(倒下或被拿起),倒下或者停止后,积分项清零(不清除会干扰下次平衡),并且电机停转 */
  28.     if( shut_down(att.rol,70.0f) || theCarStopFlag == 1)
  29.     {
  30. //#endif
  31.         PickUpisOK = 0;
  32.         for( i = 0 ; i < 3 ; i++)                                       //清除所有偏差
  33.         {
  34.             ctr.out[i] = 0;
  35.             ctr.bais[i] = 0;
  36.         }
  37.         ctr.motor[0] = 0;
  38.         ctr.motor[1] = 0;
  39.     }
  40.     else
  41.     {
  42.         ctr.motor[0] = ctr.out[0];
  43.         ctr.motor[1] = ctr.out[1];
  44.     }
  45.     if(  theCarStopFlag == 0)
  46.         motor_pwm_out(ctr.motor[0],ctr.motor[1]);                               //正常输出
  47.     else
  48.         motor_pwm_out(0,0);                                                     //关闭电机
  49. }

  50. /*
  51. * 描述  :电机转向控制
  52. * 输入  :motor1电机1的pwm,motor2电机2的pwm
  53. */
  54. void dir_config(int *motor1,int *motor2)
  55. {
  56.     if(*motor1<0) AIN1_HIGH, AIN2_LOW;
  57.     else          AIN1_LOW, AIN2_HIGH;
  58.     *motor1 = int_abs(*motor1);

  59.     if(*motor2<0) BIN1_LOW, BIN2_HIGH;
  60.     else          BIN1_HIGH, BIN2_LOW;
  61.     *motor2 = int_abs(*motor2);
  62. }
复制代码


hal_entry.c:
  1. #include "hal_data.h"
  2. #include "controller.h"
  3. #include "oled.h"
  4. #include "i2c_soft.h"
  5. #include "mpu6050.h"
  6. #include "imath.h"
  7. #include "imu.h"



  8. FSP_CPP_HEADER
  9. void R_BSP_WarmStart(bsp_warm_start_event_t event);
  10. FSP_CPP_FOOTER


  11. bsp_io_level_t p_port_value_port_104;   //ECHO引脚
  12. uint32_t Hightime_counter = 0;          //高电平时间
  13. float dis =0;                           //距离
  14. uint8_t dis_Start=0;                    //测量开始标志
  15. uint8_t Dis=0;                          //测量距离cm

  16. bsp_io_level_t p_port_value_port_212;//马达1 (B相)  通道1
  17. bsp_io_level_t p_port_value_port_213;//马达1 (A相)  通道2
  18. bsp_io_level_t p_port_value_port_408;//马达2 (A相)  通道7
  19. bsp_io_level_t p_port_value_port_409;//马达2 (B相)  通道6

  20. bsp_io_level_t p_port_value_port_015;   //ECHO引脚

  21. uint8_t direction_a=0;
  22. uint8_t direction_b=0;

  23. int hall1count_a=0;
  24. int hall1count_b=0;
  25. int hall2count_a=0;
  26. int hall2count_b=0;
  27. int hall1count=0;
  28. int hall2count=0;

  29. volatile bool uart_send_complete_flag = false;
  30. #define USART_REC_LEN       200       //定义最大接收字节数 200
  31. char  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
  32. uint16_t USART_RX_STA=0;      //接收状态标记
  33. uint8_t mode=0;               // 0平衡模式  1跟踪模式  2避障模式
  34. uint8_t move=0;               // 0停止  1前  2后  3左  4右 (方向控制仅在平衡模式下)
  35. uint8_t speed=0;              // 1加5  2减5
  36. uint16_t RxLine=0;               //接收到的数据长度


  37. #ifdef __GNUC__                                 //串口重定向
  38.     #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  39. #else
  40.     #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  41. #endif

  42. PUTCHAR_PROTOTYPE
  43. {
  44.         R_SCI_UART_Write(&g_uart9_ctrl, (uint8_t *)&ch, 1);
  45.         while(uart_send_complete_flag == false){}
  46.         uart_send_complete_flag = false;
  47.         return ch;
  48. }
  49. int _write(int fd,char *pBuffer,int size)
  50. {
  51.     for(int i=0;i<size;i++)
  52.     {
  53.         __io_putchar(*pBuffer++);
  54.     }
  55.     return size;
  56. }
  57. void user_uart9_callback(uart_callback_args_t * p_args)
  58. {
  59.     if(p_args->event == UART_EVENT_TX_COMPLETE)
  60.     {
  61.         uart_send_complete_flag = true;
  62.     }
  63. }

  64. void user_uart_callback(uart_callback_args_t * p_args)
  65. {
  66.     uint8_t RxBuff;
  67.     if(p_args->event == UART_EVENT_TX_COMPLETE)
  68.     {
  69.         uart_send_complete_flag = true;
  70.     }
  71.     if(p_args->event ==     UART_EVENT_RX_CHAR)
  72.     {
  73.         RxBuff = p_args->data;
  74.         if((USART_RX_STA&0x8000)==0)//接收未完成
  75.         {
  76.             if(USART_RX_STA&0x4000)//接收到了0x0d
  77.             {
  78.                 if(RxBuff!=0x0a)
  79.                 {
  80.                     USART_RX_STA=0;//接收错误,重新开始
  81.                     memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));  //清空缓存数组
  82.                 }
  83.                 else USART_RX_STA|=0x8000;  //接收完成了
  84.             }
  85.             else //还没收到0X0D,继续接收来的数据
  86.             {
  87.                 if(RxBuff==0x0d)USART_RX_STA|=0x4000;//接收到了0x0d
  88.                 else//接收数据
  89.                 {
  90.                     USART_RX_BUF[USART_RX_STA&0X3FFF]=RxBuff ;
  91.                     USART_RX_STA++;
  92.                     if(USART_RX_STA>(USART_REC_LEN-1))
  93.                     {
  94.                         USART_RX_STA=0;//接收数据长度超过最大接收还没收到0x0d,接收数据错误,重新开始接收
  95.                         memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));  //清空缓存数组
  96.                     }
  97.                 }
  98.             }
  99.         }
  100.     }
  101. }


  102. void ParseBluetoothMessage(char *pInput)
  103. {

  104.     if(strcmp(pInput,"mode=0")==0)mode=0;//平衡模式
  105.     if(strcmp(pInput,"mode=1")==0)mode=1;//跟踪模式
  106.     if(strcmp(pInput,"mode=2")==0)mode=2;//避障模式
  107.     if(strcmp(pInput,"move=0")==0)move=0;//停止
  108.     if(strcmp(pInput,"move=1")==0)move=1;//前进
  109.     if(strcmp(pInput,"move=2")==0)move=2;//后退
  110.     if(strcmp(pInput,"move=3")==0)move=3;//左转
  111.     if(strcmp(pInput,"move=3")==0)move=4;//右转
  112.     if(strcmp(pInput,"speed=1")==0)speed=1;//加5
  113.     if(strcmp(pInput,"speed=2")==0)speed=2;//减5
  114. }

  115. void SR04_OLED(void)
  116. {
  117.     /* 超声波测量信号 */
  118.     dis_Start=1;
  119.     R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_10, 1);
  120.     R_BSP_SoftwareDelay (20, BSP_DELAY_UNITS_MICROSECONDS);
  121.     R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_10, 0);

  122.     /* OLED显示 */
  123.     OLED_ShowString(0,0,"ValLeft :",12);
  124.     if(hall1count>=0)
  125.     {
  126.         OLED_ShowString(82,0,"+",12);
  127.         OLED_ShowNum(90,0,hall1count,3,12);
  128.     }
  129.     else
  130.     {
  131.         OLED_ShowString(82,0,"-",12);
  132.         OLED_ShowNum(90,0,-(hall1count),3,12);
  133.     }

  134.     OLED_ShowString(0,1,"ValRight:",12);
  135.     if(hall2count>=0)
  136.     {
  137.         OLED_ShowString(82,1,"+",12);
  138.         OLED_ShowNum(90,1,hall2count,3,12);
  139.     }
  140.     else
  141.     {
  142.         OLED_ShowString(82,1,"-",12);
  143.         OLED_ShowNum(90,1,-(hall2count),3,12);
  144.     }

  145.     Dis=dis;
  146.     OLED_ShowString(0,6,"dis:",12);
  147.     OLED_ShowNum(90,6,Dis,3,12);

  148.     OLED_ShowString(0,4,"Mode:",12);
  149.     OLED_ShowNum(90,4,mode,3,12);
  150. }

  151. void timer3_callback(timer_callback_args_t * p_args)
  152. {

  153. }
  154. void SR04_callback(external_irq_callback_args_t *p_args)
  155. {
  156.     timer_status_t status;//获取当前计数值
  157.     if (1 == p_args->channel)
  158.     {
  159.         /*读取端口电平状态,如果是低电平则发生的是下降沿,高电平则是上升沿*/
  160.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_04, &p_port_value_port_104);
  161.         if(dis_Start == 1)
  162.         {
  163.             if(p_port_value_port_104 == BSP_IO_LEVEL_HIGH)//上升沿
  164.             {
  165.                 R_GPT_CounterSet(&g_timer3_ctrl, 0);
  166.                 R_GPT_Start(&g_timer3_ctrl);
  167.             }
  168.             else
  169.             {
  170.                 dis_Start=0;
  171.                 R_GPT_StatusGet(&g_timer3_ctrl, &status);
  172.                 Hightime_counter =status.counter;
  173.                 dis = (float)Hightime_counter*17000/48000000 ;//(高电平时间)*340*100/2 cm   高电平时间;高电平计数次数/PCLK(48M)
  174.                 R_GPT_Stop(&g_timer3_ctrl);
  175.             }
  176.         }
  177.     }
  178. }


  179. void hall_callback(external_irq_callback_args_t *p_args)
  180. {
  181.        //马达1   A相上升沿检测到B相高电平为正相
  182.        /* 判断中断通道 */
  183.     if (2 == p_args->channel)//马达1 (A相)
  184.     {
  185.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_13, &p_port_value_port_213);
  186.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_12, &p_port_value_port_212);
  187.         if(p_port_value_port_213)//A相上升沿
  188.         {
  189.             if(p_port_value_port_212)
  190.             {
  191.                 hall1count_a++;
  192.             }
  193.             else
  194.             {
  195.                 hall1count_a--;
  196.             }
  197.         }
  198.         else//A相下降沿
  199.         {
  200.             if(p_port_value_port_212)
  201.             {
  202.                 hall1count_a--;
  203.             }
  204.             else
  205.             {
  206.                 hall1count_a++;
  207.             }
  208.         }
  209.     }
  210.     else if (3 == p_args->channel)//马达1 (B相)
  211.     {
  212.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_13, &p_port_value_port_213);
  213.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_12, &p_port_value_port_212);
  214.         if(p_port_value_port_212)//B相上升沿
  215.         {
  216.             if(p_port_value_port_213)
  217.             {
  218.                 hall1count_a--;
  219.             }
  220.             else
  221.             {
  222.                 hall1count_a++;
  223.             }
  224.         }
  225.         else//B相下降沿
  226.         {
  227.             if(p_port_value_port_213)
  228.             {
  229.                 hall1count_a++;
  230.             }
  231.             else
  232.             {
  233.                 hall1count_a--;
  234.             }
  235.         }
  236.     }

  237.     else if (7 == p_args->channel)//马达2 (A相)
  238.     {
  239.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_08, &p_port_value_port_408);
  240.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_09, &p_port_value_port_409);
  241.         if(p_port_value_port_408)//A相上升沿
  242.         {
  243.             if(p_port_value_port_409)
  244.             {
  245.                 hall2count_a++;
  246.             }
  247.             else
  248.             {
  249.                 hall2count_a--;
  250.             }
  251.         }
  252.         else//A相下降沿
  253.         {
  254.             if(p_port_value_port_409)
  255.             {
  256.                 hall2count_a--;
  257.             }
  258.             else
  259.             {
  260.                 hall2count_a++;
  261.             }
  262.         }
  263.     }
  264.     else if (6 == p_args->channel)//马达2 (B相)
  265.     {
  266.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_08, &p_port_value_port_408);
  267.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_04_PIN_09, &p_port_value_port_409);
  268.         if(p_port_value_port_409)//B相上升沿
  269.         {
  270.             if(p_port_value_port_408)
  271.             {
  272.                 hall2count_a--;
  273.             }
  274.             else
  275.             {
  276.                 hall2count_a++;
  277.             }
  278.         }
  279.         else//B相下降沿
  280.         {
  281.             if(p_port_value_port_408)
  282.             {
  283.                 hall2count_a++;
  284.             }
  285.             else
  286.             {
  287.                 hall2count_a--;
  288.             }
  289.         }
  290.     }
  291. }

  292. void timer0_callback(timer_callback_args_t * p_args)
  293. {
  294.     /* 定时器更新事件 */
  295.     if (TIMER_EVENT_CYCLE_END == p_args->event)
  296.     {
  297.         /*********************************               MPU6050              ***********************************/
  298.         get_gyro_raw();                                                         //陀螺仪数据
  299.         get_deg_s(&gyro_raw_f,&Mpu.deg_s);                                      //陀螺仪原始数据转为度为单位的速率
  300.         get_rad_s(&gyro_raw_f,&Mpu.rad_s);                                      //陀螺仪原始数据转为弧度为单位的速率
  301.         get_acc_raw();                                                          //加速度数据
  302.         acc_iir_lpf(&acc_raw_f,&acc_att_lpf,Mpu.att_acc_factor);                //姿态解算时加速度低通滤波
  303.         get_acc_g(&acc_att_lpf,&Mpu.acc_g);
  304.                                                                                 //姿态解算
  305.         mahony_update(Mpu.rad_s.x,Mpu.rad_s.y,Mpu.rad_s.z,Mpu.acc_g.x,Mpu.acc_g.y,Mpu.acc_g.z);
  306.         Matrix_ready();                                                         //姿态解算相关矩阵更新
  307.         /********************************************************************************************************/
  308.         /* 马达霍尔计数 */
  309.         hall1count=hall1count_a+hall1count_b;
  310.         hall2count=hall2count_a+hall2count_b;
  311.         hall1count_a=0;
  312.         hall1count_b=0;
  313.         hall2count_a=0;
  314.         hall2count_b=0;
  315.         /********************************************************************************************************/
  316.         /* 小车模式判断 */
  317.         //(此行不能删掉,暂时不知道为什么)难倒要加一些延时?
  318.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_15, &p_port_value_port_015);
  319. //        if(0==p_port_value_port_015)mode++;
  320. //        if(mode==3)mode=0;

  321.         ctr.pwm[0] = ctr_bal(att.rol,Mpu.deg_s.y);                        //角度直立平衡控制器
  322.         ctr.pwm[1] = ctr_vel(-hall1count,hall2count);                     //速度控制器
  323.         ctr.pwm[2] = ctr_turn(2400,Mpu.deg_s.z);                             //转向控制器

  324.         ctr.out[0] = ctr.pwm[0] + ctr.pwm[1] + ctr.pwm[2];             //电机1匹配输出
  325.         ctr.out[1] = ctr.pwm[0] + ctr.pwm[1] - ctr.pwm[2];             //电机2匹配输出
  326.         i_limit(&(ctr.out[0]),7199);                                      //输出限幅
  327.         i_limit(&(ctr.out[1]),7199);                                      //输出限幅

  328.         dir_config(&(ctr.out[0]),&(ctr.out[1]));                          //根据正负设置方向

  329.         _ctr_out();
  330.     }
  331. }


  332. /*******************************************************************************************************************//**
  333. * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
  334. * is called by main() when no RTOS is used.
  335. **********************************************************************************************************************/
  336. void hal_entry(void)
  337. {
  338.     /* TODO: add your own code here */
  339.     /* 蓝牙、串口初始化 */
  340.     R_SCI_UART_Open(&g_uart0_ctrl, &g_uart0_cfg);
  341.     //R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
  342.     /* 马达PWM初始化 */
  343.     R_GPT_Open(&g_pwm1_ctrl, &g_pwm1_cfg);
  344.     R_GPT_Open(&g_pwm2_ctrl, &g_pwm2_cfg);
  345.     R_GPT_Start(&g_pwm1_ctrl);
  346.     R_GPT_Start(&g_pwm2_ctrl);
  347.     STBY_HIGH;

  348.     /* 编码器初始化 */
  349.     R_ICU_ExternalIrqOpen(&g_external_irq0_ctrl, &g_external_irq0_cfg);//编码器A初始化
  350.     R_ICU_ExternalIrqOpen(&g_external_irq1_ctrl, &g_external_irq1_cfg);
  351.     R_ICU_ExternalIrqOpen(&g_external_irq2_ctrl, &g_external_irq2_cfg);//编码器B初始化
  352.     R_ICU_ExternalIrqOpen(&g_external_irq3_ctrl, &g_external_irq3_cfg);
  353.     R_ICU_ExternalIrqEnable(&g_external_irq0_ctrl); /* 允许中断 */
  354.     R_ICU_ExternalIrqEnable(&g_external_irq1_ctrl);
  355.     R_ICU_ExternalIrqEnable(&g_external_irq2_ctrl);
  356.     R_ICU_ExternalIrqEnable(&g_external_irq3_ctrl);

  357.     R_GPT_Open(&g_timer0_ctrl, &g_timer0_cfg);//定时器中断 9ms
  358.     R_GPT_Start(&g_timer0_ctrl);

  359.     /* 超声波初始化 */
  360.     R_GPT_Open(&g_timer3_ctrl, &g_timer3_cfg);
  361.     R_ICU_ExternalIrqOpen(&g_external_irq4_ctrl, &g_external_irq4_cfg);
  362.     R_ICU_ExternalIrqEnable(&g_external_irq4_ctrl);

  363.     OLED_Init();
  364.     mpu6050_init();
  365.     /* 检测mpu6050是否插上 */
  366.       while(1)
  367.       {
  368.           uint8_t mpuId;
  369.           mpuId = get_mpu_id();
  370.           OLED_ShowString(10,2,"mpuId:",12);
  371.           OLED_ShowNum(90,2,mpuId,4,12);
  372.   //        printf("MPU ID :%d\r\n", mpuId);
  373.           if(mpuId==0x68||mpuId==0x98)   //判断mpu6050的ID是否正确
  374.           break;
  375.           R_BSP_SoftwareDelay(50, BSP_DELAY_UNITS_MILLISECONDS);

  376.       }
  377.       get_iir_factor(&Mpu.att_acc_factor,0.005f,25);       //角度直立平衡控制器


  378.     while(1)
  379.     {
  380.         if(USART_RX_STA&0x8000)            //接收结束标志位,这个数据可以自定义,根据实际需求,这里只做示例使用,不一定是0xff
  381.         {
  382.             RxLine=USART_RX_STA&0x3fff;
  383.             ParseBluetoothMessage(USART_RX_BUF);
  384. //            printf("length=%d\r\n",RxLine);
  385. //            for(int i=0;i<RxLine;i++)printf("data:[%d] = 0x%x\r\n",i,USART_RX_BUF[i]);
  386. //            printf("\r\n\r\n");//插入换行
  387.             USART_RX_STA=0;
  388.             memset(USART_RX_BUF,0,sizeof(USART_RX_BUF));  //清空缓存数组  ##必须加这条,否则strcmp出错##
  389.         }

  390.         SR04_OLED();
  391.         R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_12, BSP_IO_LEVEL_LOW);
  392.         R_BSP_SoftwareDelay(75, BSP_DELAY_UNITS_MILLISECONDS);
  393.         SR04_OLED();
  394.         R_BSP_SoftwareDelay(75, BSP_DELAY_UNITS_MILLISECONDS);

  395.         SR04_OLED();
  396.         R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_12, BSP_IO_LEVEL_HIGH);
  397.         R_BSP_SoftwareDelay(75, BSP_DELAY_UNITS_MILLISECONDS);

  398.         SR04_OLED();
  399.         R_BSP_SoftwareDelay(75, BSP_DELAY_UNITS_MILLISECONDS);
  400.     }

  401. #if BSP_TZ_SECURE_BUILD
  402.     /* Enter non-secure code */
  403.     R_BSP_NonSecureEnter();
  404. #endif
  405. }

  406. /*******************************************************************************************************************//**
  407. * This function is called at various points during the startup process.  This implementation uses the event that is
  408. * called right before main() to set up the pins.
  409. *
  410. * @param[in]  event    Where at in the start up process the code is currently at
  411. **********************************************************************************************************************/
  412. void R_BSP_WarmStart(bsp_warm_start_event_t event)
  413. {
  414.     if (BSP_WARM_START_RESET == event)
  415.     {
  416. #if BSP_FEATURE_FLASH_LP_VERSION != 0

  417.         /* Enable reading from data flash. */
  418.         R_FACI_LP->DFLCTL = 1U;

  419.         /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
  420.          * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
  421. #endif
  422.     }

  423.     if (BSP_WARM_START_POST_C == event)
  424.     {
  425.         /* C runtime environment and system clocks are setup. */

  426.         /* Configure pins. */
  427.         R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
  428.     }
  429. }

  430. #if BSP_TZ_SECURE_BUILD

  431. FSP_CPP_HEADER
  432. BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ();

  433. /* Trustzone Secure Projects require at least one nonsecure callable function in order to build (Remove this if it is not required to build). */
  434. BSP_CMSE_NONSECURE_ENTRY void template_nonsecure_callable ()
  435. {

  436. }
  437. FSP_CPP_FOOTER

  438. #endif
复制代码


mpu6050.c:
  1. #include "mpu6050.h"
  2. #include "i2c_soft.h"
  3. #include "filter.h"
  4. #include <string.h>
  5. #include "imath.h"

  6. S16_XYZ  acc_raw = {0};                  //加速度计原始数据存储
  7. S16_XYZ  gyro_raw = {0};                 //陀螺仪原始数据存储
  8. SI_F_XYZ  gyro_raw_cal = {0};                 //陀螺仪用于校准的原始数据存储
  9. SI_F_XYZ acc_raw_f = {0};
  10. SI_F_XYZ gyro_raw_f = {0};
  11. SI_F_XYZ acc_att_lpf = {0};
  12. SI_F_XYZ gyro_lpf = {0};
  13. SI_F_XYZ gyro_offset = {0,0,0} ;         //陀螺仪零偏数据存储
  14. _Mpu6050_data Mpu = {0};

  15. _GYRO_CAL CalGyro = {0};                 //陀螺仪校准相关变量存储
  16. /*
  17. * 函数名:mpu6050_init
  18. * 描述  :初始化MOU6050配置
  19. */
  20. void mpu6050_init(void)
  21. {

  22.         IIC_Write_One_Byte(0xD0,PWR_MGMT_1, 0x00);              //唤醒mpu
  23.         tdelay_ms(100);
  24.         IIC_Write_One_Byte(0xD0,PWR_MGMT_2, 0x80);
  25.     /* when DLPF is disabled( DLPF_CFG=0 or 7),陀螺仪输出频率 = 8kHz;
  26.        when DLPFis enabled,陀螺仪输出频率 = 1KHz
  27.        fs(采样频率) = 陀螺仪输出频率 / (1 + SMPLRT_DIV)*/
  28.         IIC_Write_One_Byte(0xD0,SMPLRT_DIV, 0x00);                        //sample rate.  Fsample= 1Khz/(<this value>+1) = 1000Hz
  29.         IIC_Write_One_Byte(0xD0,MPU_CONFIG, 0x03);              //内部低通  acc:44hz        gyro:42hz
  30.         IIC_Write_One_Byte(0xD0,GYRO_CONFIG, 0x18);                            // gyro scale  :+-2000°/s
  31.         IIC_Write_One_Byte(0xD0,ACCEL_CONFIG, 0x10);                        // Accel scale :+-8g (65536/16=4096 LSB/g)
  32. }
  33. /*
  34. * 描述  :两字节数据读取并合成一个16位数据
  35. * 输入  :REG_Address寄存器地址
  36. * 返回  :合成的16位数据
  37. */
  38. static int get_data(unsigned char REG_Address)
  39. {
  40.         unsigned char H,L;
  41.         H = IIC_Read_One_Byte(0xD0,REG_Address);
  42.         L = IIC_Read_One_Byte(0xD0,REG_Address+1);
  43.         return ((H<<8)+L);
  44. }
  45. /*
  46. * 描述  :读取mpu6050的ID
  47. * 返回  :芯片ID
  48. */
  49. uint8_t get_mpu_id(void)
  50. {
  51.     uint8_t mpu_id;
  52.     mpu_id = IIC_Read_One_Byte(0xD0,WHO_AM_I);
  53.     return mpu_id;
  54. }
  55. /*
  56. * 函数名:get_acc_raw
  57. * 描述  :读取加速度计三轴原始数据
  58. * 输入  :
  59. * 返回  :
  60. */
  61. void get_acc_raw(void)
  62. {
  63.     acc_raw.x = get_data(ACCEL_XOUT_H);
  64.     acc_raw.y = get_data(ACCEL_YOUT_H);
  65.     acc_raw.z = get_data(ACCEL_ZOUT_H);

  66.         acc_raw_f.x = (float)acc_raw.x;
  67.         acc_raw_f.y = (float)acc_raw.y;
  68.         acc_raw_f.z = (float)acc_raw.z;
  69. }
  70. /*
  71. * 变量名:gyro_30hz_parameter
  72. * 描述  :巴特沃斯低通滤波器参数
  73. * 输入  :
  74. * 返回  :
  75. */
  76. _Butterworth_parameter gyro_30hz_parameter =
  77. {
  78.     //200hz---30hz
  79.     1,  -0.7477891782585,    0.272214937925,
  80.     0.1311064399166,   0.2622128798333,   0.1311064399166
  81. };

  82. _Butterworth_data   gyro_butter_data[3];
  83. /*
  84. * 函数名:get_gyro_raw
  85. * 描述  :读取陀螺仪三轴原始数据 & 进行校准 & 低通滤波
  86. */
  87. void get_gyro_raw(void)
  88. {
  89.     gyro_raw.x = get_data(GYRO_XOUT_H) - gyro_offset.x;
  90.     gyro_raw.y = get_data(GYRO_YOUT_H) - gyro_offset.y;
  91.     gyro_raw.z = get_data(GYRO_ZOUT_H) - gyro_offset.z;

  92.     gyro_raw_f.x = (float)butterworth_lpf(((float)gyro_raw.x),&gyro_butter_data[0],&gyro_30hz_parameter);
  93.     gyro_raw_f.y = (float)butterworth_lpf(((float)gyro_raw.y),&gyro_butter_data[1],&gyro_30hz_parameter);
  94.     gyro_raw_f.z = (float)butterworth_lpf(((float)gyro_raw.z),&gyro_butter_data[2],&gyro_30hz_parameter);

  95.     gyro_raw_cal.x = (float)get_data(GYRO_XOUT_H);
  96.     gyro_raw_cal.y = (float)get_data(GYRO_YOUT_H);
  97.     gyro_raw_cal.z = (float)get_data(GYRO_ZOUT_H);
  98. }
  99. /*         get_iir_factor(&Mpu.att_acc_factor,0.005f,25);
  100. * 描述  :求取IIR滤波器的滤波因子
  101. * 输入  :out_factor滤波因子首地址,Time任务执行周期,Cut_Off滤波截止频率
  102. */
  103. void get_iir_factor(float *out_factor,float Time, float Cut_Off)
  104. {
  105.         *out_factor = Time /( Time + 1/(2.0f * PI * Cut_Off) );
  106. }
  107. //IIR低通滤波器(加速度)
  108. void acc_iir_lpf(SI_F_XYZ *acc_in,SI_F_XYZ *acc_out,float lpf_factor)
  109. {
  110.         acc_out->x = acc_out->x + lpf_factor*(acc_in->x - acc_out->x);
  111.         acc_out->y = acc_out->y + lpf_factor*(acc_in->y - acc_out->y);
  112.         acc_out->z = acc_out->z + lpf_factor*(acc_in->z - acc_out->z);
  113. }
  114. //加速度计滤波参数
  115. _Butterworth_parameter acc_5hz_parameter =
  116. {
  117.     1,                  -1.778631777825,    0.8008026466657,
  118.     0.005542717210281,   0.01108543442056,  0.005542717210281
  119. };

  120. _Butterworth_data   acc_butter_data[3];
  121. /*
  122. * 描述  :巴特沃斯加速度低通滤波
  123. * 输入  :acc_in滤波前的加速度,acc_out滤波后的输出加速度数据
  124. */
  125. void acc_butterworth_lpf(SI_F_XYZ *acc_in,SI_F_XYZ *acc_out)
  126. {
  127.     acc_out->x = butterworth_lpf(acc_in->x,&acc_butter_data[0],&acc_5hz_parameter);
  128.     acc_out->y = butterworth_lpf(acc_in->y,&acc_butter_data[1],&acc_5hz_parameter);
  129.     acc_out->z = butterworth_lpf(acc_in->z,&acc_butter_data[2],&acc_5hz_parameter);
  130. }
  131. /*
  132. * 描述  :原始加速度转为重力加速度g为单位数据
  133. * 输入  :acc_in原始的加速度,acc_out以g为单位的加速度数据
  134. */
  135. void get_acc_g(SI_F_XYZ *acc_in,SI_F_XYZ *acc_out)
  136. {
  137.         acc_out->x = (float)(acc_in->x * acc_raw_to_g);
  138.         acc_out->y = (float)(acc_in->y * acc_raw_to_g);
  139.         acc_out->z = (float)(acc_in->z * acc_raw_to_g);
  140. }
  141. /*
  142. * 描述  :原始陀螺仪数据转为弧度/秒为单位的数据
  143. * 输入  :gyro_in原始的陀螺仪数据,gyro_out以rad/s为单位的陀螺仪数据
  144. */
  145. void get_rad_s(SI_F_XYZ *gyro_in,SI_F_XYZ *gyro_out)
  146. {
  147.         gyro_out->x = (float)(gyro_in->x * gyro_raw_to_radian_s);
  148.         gyro_out->y = (float)(gyro_in->y * gyro_raw_to_radian_s);
  149.         gyro_out->z = (float)(gyro_in->z * gyro_raw_to_radian_s);
  150. }
  151. /*
  152. * 描述  :原始陀螺仪数据转为度/秒为单位的数据
  153. * 输入  :gyro_in原始的陀螺仪数据首地址,gyro_deg_out以deg/s为单位的陀螺仪数据首地址
  154. */
  155. void get_deg_s(SI_F_XYZ *gyro_in,SI_F_XYZ *gyro_deg_out)
  156. {
  157.         gyro_deg_out->x = (float)(gyro_in->x * gyro_raw_to_deg_s);
  158.         gyro_deg_out->y = (float)(gyro_in->y * gyro_raw_to_deg_s);
  159.         gyro_deg_out->z = (float)(gyro_in->z * gyro_raw_to_deg_s);
  160. }
复制代码


oled.c
  1. #include "oled.h"
  2. #include "oledfont.h"

  3. void IICO_Start()
  4. {
  5.         OLED_SCLK_Set() ;
  6.         OLED_SDIN_Set();
  7.         OLED_SDIN_Clr();
  8.         OLED_SCLK_Clr();   
  9. }
  10. void IICO_Stop()
  11. {
  12.     OLED_SCLK_Set() ;
  13. //        OLED_SCLK_Clr();
  14.         OLED_SDIN_Clr();
  15.         OLED_SDIN_Set();       
  16. }
  17. void IICO_Wait_Ack()
  18. {

  19. /*        while(1)
  20.         {
  21.                 if(!OLED_SDA)                               
  22.                 {
  23.                         return;
  24.                 }
  25.         }
  26. */
  27.         OLED_SCLK_Set() ;
  28.         OLED_SCLK_Clr();
  29. }
  30. void Write_IIC_Byte(unsigned char IIC_Byte)
  31. {
  32.         unsigned char i;
  33.         unsigned char m,da;
  34.         da=IIC_Byte;
  35.         OLED_SCLK_Clr();
  36.         for(i=0;i<8;i++)               
  37.         {
  38.         m=da;
  39.                 //        OLED_SCLK_Clr();
  40.                 m=m&0x80;
  41.                 if(m==0x80)
  42.                 {
  43.             OLED_SDIN_Set();
  44.         }
  45.         else
  46.         OLED_SDIN_Clr();
  47.         da=da<<1;
  48.         OLED_SCLK_Set();
  49.         OLED_SCLK_Clr();
  50.     }
  51. }
  52. void Write_IIC_Command(unsigned char IIC_Command)
  53. {
  54.     IICO_Start();
  55.     Write_IIC_Byte(0x78);            //Slave address,SA0=0
  56.     IICO_Wait_Ack();       
  57.     Write_IIC_Byte(0x00);                        //write command
  58.     IICO_Wait_Ack();       
  59.     Write_IIC_Byte(IIC_Command);
  60.     IICO_Wait_Ack();       
  61.     IICO_Stop();
  62. }
  63. void Write_IIC_Data(unsigned char IIC_Data)
  64. {
  65.     IICO_Start();
  66.     Write_IIC_Byte(0x78);                        //D/C#=0; R/W#=0
  67.     IICO_Wait_Ack();       
  68.     Write_IIC_Byte(0x40);                        //write data
  69.     IICO_Wait_Ack();       
  70.     Write_IIC_Byte(IIC_Data);
  71.     IICO_Wait_Ack();       
  72.     IICO_Stop();
  73. }
  74. void OLED_WR_Byte(unsigned dat,unsigned cmd)
  75. {
  76.         if(cmd)Write_IIC_Data(dat);       
  77.         else Write_IIC_Command(dat);
  78. }
  79. //坐标设置
  80. void OLED_Set_Pos(unsigned char x, unsigned char y)
  81. {
  82.         OLED_WR_Byte(0xb0+y,OLED_CMD);
  83.         OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
  84.         OLED_WR_Byte((x&0x0f),OLED_CMD);
  85. }             
  86. //开启OLED显示  
  87. void OLED_Display_On(void)
  88. {
  89.         OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  90.         OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
  91.         OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
  92. }
  93. //关闭OLED显示   
  94. void OLED_Display_Off(void)
  95. {
  96.         OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDCÃüÁî
  97.         OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
  98.         OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
  99. }                                  
  100. void OLED_Clear(void)  
  101. {  
  102.         uint8_t i,n;
  103.         for(i=0;i<8;i++)  
  104.         {  
  105.                 OLED_WR_Byte (0xb0+i,OLED_CMD);   
  106.                 OLED_WR_Byte (0x00,OLED_CMD);      
  107.                 OLED_WR_Byte (0x10,OLED_CMD);         
  108.                 for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
  109.         }
  110. }
  111. void OLED_On(void)  
  112. {  
  113.     uint8_t i,n;
  114.         for(i=0;i<8;i++)  
  115.         {  
  116.                 OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址0-7
  117.                 OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置-列高地址
  118.                 OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置-列低地址
  119.                 for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
  120.     }   
  121. }
  122. //在指定位置显示一个字符
  123. //x:0~127  y:0~63
  124. //mode:0,反白显示;1,正常显示         
  125. //size:选择字体 16/12
  126. void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr,uint8_t Char_Size)
  127. {             
  128.     unsigned char c=0,i=0;       
  129.     c=chr-' ';                              //得到偏移后的地址                       
  130.     if(x>Max_Column-1)
  131.     {
  132.         x=0;
  133.         y=y+2;
  134.     }
  135.     if(Char_Size ==16)
  136.     {
  137.         OLED_Set_Pos(x,y);       
  138.         for(i=0;i<8;i++)
  139.             OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
  140.         OLED_Set_Pos(x,y+1);
  141.         for(i=0;i<8;i++)
  142.             OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
  143.     }
  144.     else
  145.     {       
  146.         OLED_Set_Pos(x,y);
  147.         for(i=0;i<6;i++)
  148.             OLED_WR_Byte(F6x8[c][i],OLED_DATA);                       
  149.     }
  150. }
  151. uint32_t oled_pow(uint8_t m,uint8_t n)//m^n函数
  152. {
  153.     uint32_t result=1;
  154.         while(n--)result*=m;   
  155.         return result;
  156. }                                  
  157. //显示两个数字
  158. //x,y :起点坐标
  159. //len :数字的位数
  160. //size:字体大小
  161. //mode:模式0,填充模式;1,叠加模式
  162. //num:数值(0~4294967295);                           
  163. void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size2)
  164. {                
  165.     uint8_t t,temp;
  166.     uint8_t enshow=0;
  167.         for(t=0;t<len;t++)
  168.         {
  169.                 temp=(num/oled_pow(10,len-t-1))%10;
  170.                 if(enshow==0&&t<(len-1))
  171.                 {
  172.                         if(temp==0)
  173.                         {
  174.                                 OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
  175.                                 continue;
  176.                         }
  177.                         else enshow=1;           
  178.                 }
  179.                  OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
  180.         }
  181. }
  182. void OLED_ShowString(uint8_t x,uint8_t y,uint8_t *chr,uint8_t Char_Size)    //显示一个字符号串
  183. {
  184.         unsigned char j=0;
  185.         while (chr[j]!='\0')
  186.         {
  187.                 OLED_ShowChar(x,y,chr[j],Char_Size);
  188.                 x+=8;
  189.                 if(x>120){x=0;y+=2;}j++;
  190.         }
  191. }
  192. void OLED_ShowCHinese(uint8_t x,uint8_t y,uint8_t no)                  //显示汉字
  193. {                                  
  194.     uint8_t t,adder=0;
  195.         OLED_Set_Pos(x,y);       
  196.     for(t=0;t<16;t++)
  197.     {
  198.         OLED_WR_Byte(Hzk[2*no][t],OLED_DATA);
  199.         adder+=1;
  200.     }       
  201.     OLED_Set_Pos(x,y+1);       
  202.     for(t=0;t<16;t++)
  203.     {       
  204.         OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA);
  205.         adder+=1;
  206.     }                                       
  207. }            
  208. void OLED_Init(void)                                                //初始化SSD1306               
  209. {          

  210. //        tdelay_ms(800);
  211.         OLED_WR_Byte(0xAE,OLED_CMD);//--display off
  212.         OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
  213.         OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
  214.         OLED_WR_Byte(0x40,OLED_CMD);//--set start line address  
  215.         OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
  216.         OLED_WR_Byte(0x81,OLED_CMD); // contract control
  217.         OLED_WR_Byte(0xFF,OLED_CMD);//--128   
  218.         OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
  219.         OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
  220.         OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
  221.         OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
  222.         OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
  223.         OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
  224.         OLED_WR_Byte(0x00,OLED_CMD);//       
  225.         OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
  226.         OLED_WR_Byte(0x80,OLED_CMD);//       
  227.         OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
  228.         OLED_WR_Byte(0x05,OLED_CMD);//       
  229.         OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
  230.         OLED_WR_Byte(0xF1,OLED_CMD);//       
  231.         OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
  232.         OLED_WR_Byte(0x12,OLED_CMD);//       
  233.         OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
  234.         OLED_WR_Byte(0x30,OLED_CMD);//       
  235.         OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
  236.         OLED_WR_Byte(0x14,OLED_CMD);//       
  237.         OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
  238.    
  239.     OLED_Clear() ;
  240. }  
复制代码


超声波检测距离与oled显示:
  1. void SR04_OLED(void)
  2. {
  3.     /* 超声波测量信号 */
  4.     dis_Start=1;
  5.     R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_10, 1);
  6.     R_BSP_SoftwareDelay (20, BSP_DELAY_UNITS_MICROSECONDS);
  7.     R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_00_PIN_10, 0);

  8.     /* OLED显示 */
  9.     OLED_ShowString(0,0,"ValLeft :",12);
  10.     if(hall1count>=0)
  11.     {
  12.         OLED_ShowString(82,0,"+",12);
  13.         OLED_ShowNum(90,0,hall1count,3,12);
  14.     }
  15.     else
  16.     {
  17.         OLED_ShowString(82,0,"-",12);
  18.         OLED_ShowNum(90,0,-(hall1count),3,12);
  19.     }

  20.     OLED_ShowString(0,1,"ValRight:",12);
  21.     if(hall2count>=0)
  22.     {
  23.         OLED_ShowString(82,1,"+",12);
  24.         OLED_ShowNum(90,1,hall2count,3,12);
  25.     }
  26.     else
  27.     {
  28.         OLED_ShowString(82,1,"-",12);
  29.         OLED_ShowNum(90,1,-(hall2count),3,12);
  30.     }

  31.     Dis=dis;
  32.     OLED_ShowString(0,6,"dis:",12);
  33.     OLED_ShowNum(90,6,Dis,3,12);

  34.     OLED_ShowString(0,4,"Mode:",12);
  35.     OLED_ShowNum(90,4,mode,3,12);
  36. }

  37. void SR04_callback(external_irq_callback_args_t *p_args)
  38. {
  39.     timer_status_t status;//获取当前计数值
  40.     if (1 == p_args->channel)
  41.     {
  42.         /*读取端口电平状态,如果是低电平则发生的是下降沿,高电平则是上升沿*/
  43.         R_IOPORT_PinRead(&g_ioport_ctrl, BSP_IO_PORT_01_PIN_04, &p_port_value_port_104);
  44.         if(dis_Start == 1)
  45.         {
  46.             if(p_port_value_port_104 == BSP_IO_LEVEL_HIGH)//上升沿
  47.             {
  48.                 R_GPT_CounterSet(&g_timer3_ctrl, 0);
  49.                 R_GPT_Start(&g_timer3_ctrl);
  50.             }
  51.             else
  52.             {
  53.                 dis_Start=0;
  54.                 R_GPT_StatusGet(&g_timer3_ctrl, &status);
  55.                 Hightime_counter =status.counter;
  56.                 dis = (float)Hightime_counter*17000/48000000 ;//(高电平时间)*340*100/2 cm   高电平时间;高电平计数次数/PCLK(48M)
  57.                 R_GPT_Stop(&g_timer3_ctrl);
  58.             }
  59.         }
  60.     }
  61. }
复制代码


回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-21 23:47:30 | 显示全部楼层

用到的资源:
1692632806551.jpg
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-8-27 23:34:24 | 显示全部楼层

不同参数的电机要更改不同的PID参数,甚至可能要调整定时器时间。
工程代码: RA2E1_Car.zip (1.45 MB, 下载次数: 56)

想要学习平衡小车的,建议B站观看:(很详细,讲解很棒)
https://www.bilibili.com/video/B ... 99bc20cf9fbfd79c4c9

小板原理图,小板打板文件:
克哈RA2平衡车小板.pdf (204.78 KB, 下载次数: 26)
克哈RA2平衡车小板.zip (92.42 KB, 下载次数: 19)
防止盗卖行为,底板就不放上来了,有兴趣的直接按图做一个。
回复 支持 反对

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-11-23 17:37 , Processed in 0.049941 second(s), 28 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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