本例程接纳了HAL库停止项目开发(次要利用软件CubexMX和keil5),文章末尾会有代码开源,欢送列位对文章停止斧正和切磋。

基于PID的减速电机控造一、 硬件模块与原理图1、硬件构成

硬件构成:stm32f103c8t6最小系统板;0.96寸LED12864(I2C通信形式);智能小车12v挪动电源;25GA370曲流减速电机(带霍尔编码器);JDY-31蓝牙模块;L298N电机驱动模块;杜邦线若干;1个面包板;

图片如下:

stm32做PID算法控制减速直流电机  第1张

2、模块阐发1、L298N电机驱动模块stm32做PID算法控制减速直流电机  第2张

stm32做PID算法控制减速直流电机  第3张

1.模块可驱动两路曲流电机,输出A和B各接不断流电机即可;

2.若利用12V供电,将12V供电端口及GND接上电源正负即可,同时5V供电端能够做为最小系统板的输入电源;

3.若不需要利用PWM调速,只需要控造电机正反转,则逻辑A与B跳线帽插上即可,相当于始末使能;

4.若需要利用PWM调速,需将跳线帽拔起,将使能端接上单片机IO口。(按时器IO口,PWM输出形式);

5.逻辑输入四个端口IN1、IN2、IN3、IN4接单片机四个IO口,每两个端口控造的一路电机。

温馨提醒: 出格不建议新手或者资金有限的情况下,利用电机驱动模块曲连废品开发板,很容易烧坏。

原因:(1) 因为电机的特征,电机在堵转或者高负载下,电流会增大,可能会影响到单片机。(2)新手玩单片机可能呈现短路等情况,很容易板子冒烟;

L298N的动弹逻辑图:

stm32做PID算法控制减速直流电机  第4张

2、0.96寸OLED(I2C通信)stm32做PID算法控制减速直流电机  第5张

stm32做PID算法控制减速直流电机  第6张

(1)目前市道次要分为OLED与LCD那2种屏幕;

(2)OLED自觉光特征,LCD都要背光,而OLED不需要,因为它是自觉光。如许同样的显示,OLED效果要来得好一些;

(3)多种接口体例:6800,8080两种并行接口体例,4线的穿行SPI接口,IIC接口体例(2线);

(4)不要接过高电压,3.3V就能够一般工做了;

(5)OLED不敷之处是做大之后成本较高。

本尝试接纳了0.96寸OLED的屏幕(通信体例IIC),4个接线柱(SCL,SDA,GND,VCC); IIC通信实现体例: IIC(Inter-Integrated Circuit)总线是一种由 PHILIPS 公司开发的两线式串行总线,用于毗连微控造器及其外围设备。它是由数据线 SDA 和时钟 SCL 构成的串行总线,可发送和领受数据。高速 IIC 总线一般可达 400kbps 以上。

模仿IIC通信:

I2C 是撑持多从机的,也就是一个 I2C 控造器下能够挂多个 I2C 从设备,那些差别的 I2C从设备有差别的器件地址,如许 I2C 主控造器就能够通过 I2C 设备的器件地址拜候指定的 I2C设备了。SDA 和SCL 那两根线必需要接一个上拉电阻,一般是 4.7K。其余的 I2C 从器件都挂接到 SDA 和 SCL 那两根线上,如许就能够通过 SDA 和 SCL 那两根线来拜候多个 I2C设备。

I2C 协议:(1)起始位;(2)停行位;(3)数据传输;(4)应答信号;(5)I2C 写时序;(6)I2C 读时序

I2C 写时序:

stm32做PID算法控制减速直流电机  第7张

1)、起头信号。

2)、发送 I2C 设备地址,每个 I2C 器件都有一个设备地址,通过发送详细的设备地址来决

定拜候哪个 I2C 器件。那是一个 8 位的数据,此中高 7 位是设备地址,最初 1 位是读写位,为

1 的话暗示那是一个读操做,为 0 的话暗示那是一个写操做。

3)、 I2C 器件地址后面跟着一个读写位,为 0 暗示写操做,为 1 暗示读操做。

4)、从机发送的 ACK 应答信号。

5)、从头发送起头信号。

6)、发送要写写入数据的存放器地址。

7)、从机发送的 ACK 应答信号。

8)、发送要写入存放器的数据。

9)、从机发送的 ACK 应答信号。

10)、停行信号。

I2C 读时序:

stm32做PID算法控制减速直流电机  第8张

I2C 单字节读时序比写时序要复杂一点,读时序分为 4 大步,第一步是发送设备地址,第二步是发送要读取的存放器地址,第三步从头发送设备地址,最初一步就是 I2C 从器件输出要读取的存放器值,我们详细来看一下那几步。

1)、主机发送起始信号。

2)、主机发送要读取的 I2C 从设备地址。

3)、读写控造位,因为是向 I2C 从设备发送数据,因而是写信号。

4)、从机发送的 ACK 应答信号。

5)、从头发送 START 信号。

6)、主机发送要读取的存放器地址。

7)、从机发送的 ACK 应答信号。

8)、从头发送 START 信号。

9)、从头发送要读取的 I2C 从设备地址。

10)、读写控造位,那里是读信号,暗示接下来是从 I2C 从设备里面读取数据。

11)、从机发送的 ACK 应答信号。

12)、从 I2C 器件里面读取到的数据。

13)、主机发出 NO ACK 信号,暗示读取完成,不需要从机再发送 ACK 信号了。

14)、主机发出 STOP 信号,停行 I2C 通信。

3、JDY-31蓝牙模块stm32做PID算法控制减速直流电机  第9张

stm32做PID算法控制减速直流电机  第10张

市场上蓝牙模块有良多,常见的JDY-xx,HC-xx等系列。其实看似高级的蓝牙功用背后就是简单的串口通信;

USART 的全称是 Universal Synchronous/Asynchronous Receiver/Transmitter,也就是同步/异步串行收发器。比拟 UART 多了一个同步的功用,在硬件上表现出来的就是多了一条时钟线。一般 USART 是能够做为 UART 利用的,也就是不利用其同步的功用。

串口通信协议:

数据包:串口通信的数据包由发送设备通过本身的TXD接口传输到领受设备得RXD接口,在协议层中规定了数据包的内容,详细包罗起始位、主体数据(8位或9位)、校验位以及停行位,通信的两边必需将数据包的格局约定一致才气一般收发数据。

详细如图所示:

stm32做PID算法控制减速直流电机  第11张

波特率:因为异步通信中没有时钟信号,所以领受两边要约定好波特率,即每秒传输的码元个数,以便对信号停止解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化构造体来实现。

留意:MCU设置的波特率大小要与蓝牙APP设置的大小一致!

4、6线减速电机(带编码器)模块:

市道上电机有良多,常用的有步进电机,曲流减速电机,伺服电机等等; 编码器:用来丈量电机转速的仪器元件,常见的有:霍尔编码器,光电编码器等 电机的驱动原理很简单,给电压差即可使得电机动弹,调速则操纵PWM调理发。

stm32做PID算法控制减速直流电机  第12张

编码器原理: 编码器是一种将角位移或者角速度转换成一串电数字脉冲的扭转式传感器。 编码器工做原理: 霍尔编码器是有霍尔马盘和霍尔元件构成。霍尔马盘是在必然曲径的圆板上等分的安插有差别的磁极。霍尔马盘与电动机同轴,电动机扭转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在必然相位差的方波信号。

stm32做PID算法控制减速直流电机  第13张

stm32做PID算法控制减速直流电机  第14张

留意:通过判断A与B相哪一位在前,即可判断出正转仍是反转

二、CubexMX设置

利用的MCU为stm32f103c8t6:

stm32做PID算法控制减速直流电机  第15张

RCC:

stm32做PID算法控制减速直流电机  第16张

SYS:

stm32做PID算法控制减速直流电机  第17张

留意:Debug那里必然要设置成Serial Wire不然可能呈现芯片自锁

GPIO设置:

stm32做PID算法控制减速直流电机  第18张

按时TIM2用来测速与丈量正转反转(计数器形式)

stm32做PID算法控制减速直流电机  第19张

按时3:PWM调理

stm32做PID算法控制减速直流电机  第20张

I2C:

stm32做PID算法控制减速直流电机  第21张

USART1:

stm32做PID算法控制减速直流电机  第22张

之后根据本身习惯生成初始化文件

三、代码

主动生成的:

stm32做PID算法控制减速直流电机  第23张

需要本身编写的:

stm32做PID算法控制减速直流电机  第24张

I2C代码:

#include "oled.h"#include "asc.h"#include "main.h"void WriteCmd(unsigned char I2C_Command)//??? { HAL_I2C_Mem_Write(&hi2c2,OLED0561_ADD,COM,I2C_MEMADD_SIZE_8BIT,&I2C_Command,1,100); } void WriteDat(unsigned char I2C_Data)//??? { HAL_I2C_Mem_Write(&hi2c2,OLED0561_ADD,DAT,I2C_MEMADD_SIZE_8BIT,&I2C_Data,1,100); } void OLED_Init(void){ HAL_Delay(100); //???????? WriteCmd(0xAE); //display off WriteCmd(0x20); //Set Memory Addressing Mode WriteCmd(0x10); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid WriteCmd(0xb0); //Set Page Start Address for Page Addressing Mode,0-7 WriteCmd(0xc8); //Set COM Output Scan Direction WriteCmd(0x00); //---set low column address WriteCmd(0x10); //---set high column address WriteCmd(0x40); //--set start line address WriteCmd(0x81); //--set contrast control register WriteCmd(0xff); //???? 0x00~0xff WriteCmd(0xa1); //--set segment re-map 0 to 127 WriteCmd(0xa6); //--set normal display WriteCmd(0xa8); //--set multiplex ratio(1 to 64) WriteCmd(0x3F); // WriteCmd(0xa4); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content WriteCmd(0xd3); //-set display offset WriteCmd(0x00); //-not offset WriteCmd(0xd5); //--set display clock divide ratio/oscillator frequency WriteCmd(0xf0); //--set divide ratio WriteCmd(0xd9); //--set PRe-charge PEriod WriteCmd(0x22); // WriteCmd(0xda); //--set com pins hardware configuration WriteCmd(0x12); WriteCmd(0xdb); //--set vcomh WriteCmd(0x20); //0x20,0.77xVcc WriteCmd(0x8d); //--set DC-DC enable WriteCmd(0x14); // WriteCmd(0xaf); //--turn on oled panel} void OLED_SetPos(unsigned char x, unsigned char y) //???????{ WriteCmd(0xb0+y); WriteCmd(((x&0xf0)>>4)|0x10); WriteCmd((x&0x0f)|0x01);} void OLED_Fill(unsigned char fill_Data)//????{ unsigned char m,n; for(m=0;m<8;m++) { WriteCmd(0xb0+m); //page0-page1 WriteCmd(0x00); //low column start address WriteCmd(0x10); //high column start address for(n=0;n<128;n++) { WriteDat(fill_Data); } }} void OLED_CLS(void)//??{ OLED_Fill(0x00);} void OLED_ON(void){ WriteCmd(0X8D); //????? WriteCmd(0X14); //????? WriteCmd(0XAF); //OLED??} void OLED_OFF(void){ WriteCmd(0X8D); //????? WriteCmd(0X10); //????? WriteCmd(0XAE); //OLED??} // Parameters : x,y -- ?????(x:0~127, y:0~7); ch[] -- ???????; TextSize -- ????(1:6*8 ; 2:8*16)// Description : ??codetab.h??ASCII??,?6*8?8*16???void OLED_ShowStr(unsigned char x, unsigned char y, unsigned char ch[], unsigned char TextSize){ unsigned char c = 0,i = 0,j = 0; switch(TextSize) { case 1: { while(ch[j] != '\0') { c = ch[j] - 32; if(x > 126) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<6;i++) WriteDat(F6x8[c][i]); x += 6; j++; } }break; case 2: { while(ch[j] != '\0') { c = ch[j] - 32; if(x > 120) { x = 0; y++; } OLED_SetPos(x,y); for(i=0;i<8;i++) WriteDat(F8X16[c*16+i]); OLED_SetPos(x,y+1); for(i=0;i<8;i++) WriteDat(F8X16[c*16+i+8]); x += 8; j++; } }break; }} // Parameters : x,y -- ?????(x:0~127, y:0~7); N:???.h????// Description : ??ASCII_8x16.h????,16*16??void OLED_ShowCN(unsigned char x, unsigned char y, unsigned char N){ unsigned char wm=0; unsigned int adder=32*N; OLED_SetPos(x , y); for(wm = 0;wm < 16;wm++) { WriteDat(F16x16[adder]); adder += 1; } OLED_SetPos(x,y + 1); for(wm = 0;wm < 16;wm++) { WriteDat(F16x16[adder]); adder += 1; }} // ????????????????,????????“??——???——????”??????ascll.h?????(????)//???????:x:????? // y:???(??0-7) // begin:????????????????ascll.c??????? // num:????????// ????“??”,??????????????????0,1,???0,??????,??:x:0,y:2,begin:0,num:2void OLED_ShowCN_STR(u8 x , u8 y , u8 begin , u8 num){ u8 i; for(i=0;i<num;i++){OLED_ShowCN(i*16+x,y,i+begin);} //OLED????} // Parameters : x0,y0 -- ?????(x0:0~127, y0:0~7); x1,y1 -- ?????(???)???(x1:1~128,y1:1~8)// Description : ??BMP??void OLED_DrawBMP(unsigned char x0,unsigned char y0,unsigned char x1,unsigned char y1,unsigned char BMP[]){ unsigned int j=0; unsigned char x,y; if(y1%8==0) y = y1/8; else y = y1/8 + 1; for(y=y0;y<y1;y++) { OLED_SetPos(x0,y); for(x=x0;x<x1;x++) { WriteDat(BMP[j++]); } }} void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size){ unsigned char c=0,i=0; c=chr-' ';//??????? if(x>128-1){x=0;y=y+2;} if(Char_Size ==16) { OLED_SetPos(x,y); for(i=0;i<8;i++) WriteDat(F8X16[c*16+i]); OLED_SetPos(x,y+1); for(i=0;i<8;i++) WriteDat(F8X16[c*16+i+8]); } else { OLED_SetPos(x,y); for(i=0;i<6;i++) WriteDat(F6x8[c][i]); }}u32 oled_pow(u8 m,u8 n){ u32 result=1; while(n--)result*=m; return result;} //??2???//x,y :???? //len :?????//size:????//mode:?? 0,????;1,????//num:??(0~4294967295); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2){ u8 t,temp; u8 enshow=0; for(t=0;t<len;t++) { temp=(num/oled_pow(10,len-t-1))%10; if(enshow==0&&t<(len-1)) { if(temp==0) { OLED_ShowChar(x+(size2/2)*t,y,' ',size2); continue; }else enshow=1; } OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); }}

UART代码:

#include "uart.h" uint8_t USART1_RX_BUF[USART1_REC_LEN];//????,??USART_REC_LEN???.uint16_t USART1_RX_STA=0;//??????//bit15:??????,bit14~0:??????????uint8_t USART1_NewData;//?????????1???????? extern int flag; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//????????{ if(huart ==&huart1) { if((USART1_RX_STA&0x8000)==0)//????? { if(USART1_NewData==0x5A)//????0x5A { USART1_RX_STA|=0x8000; //?????,?USART2_RX_STA??bit15(15?)?1 } else { USART1_RX_BUF[USART1_RX_STA&0X7FFF]=USART1_NewData; if(USART1_RX_BUF[1] == 0x01) { flag = 2; } USART1_RX_STA++; //???????1 if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//??????,?????? } } HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); }}

常规的编写如上,但是本人的MCU存在问题,单片机并未领受到预设的数据。

所以,本人项目中接纳了下方代码:

#include "uart.h" uint8_t USART1_RX_BUF[USART1_REC_LEN];//????,??USART_REC_LEN???.uint16_t USART1_RX_STA=0;//??????//bit15:??????,bit14~0:??????????uint8_t USART1_NewData;//?????????1???????? extern int flag; void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//????????{ if(huart ==&huart1) { USART1_RX_BUF[USART1_RX_STA&0X7FFF]=USART1_NewData; USART1_RX_STA++; //???????1 if(USART1_RX_STA>(USART1_REC_LEN-1))USART1_RX_STA=0;//??????,?????? if(USART1_RX_BUF[USART1_RX_STA-4] == 0xA0) { flag = 1; } if(USART1_RX_BUF[USART1_RX_STA-4] == 0x90) { flag = 2; } if(USART1_RX_BUF[USART1_RX_STA-4] == 0xD0) { flag = 3; } if(USART1_RX_BUF[USART1_RX_STA-4] == 0x88) { flag = 4; } if(USART1_RX_BUF[USART1_RX_STA-4] == 0x48) { flag = 5; } HAL_UART_Receive_IT(&huart1,(uint8_t *)&USART1_NewData,1); }}

若是各人本身利用的花,能够按照本身的蓝牙APP写那段法式,有问题欢送留言

Motor代码:

#include "motor.h" void MOTOR_GO(){ __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1,3000); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);} void MOTOR_BACK(){ HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);} void MOTOR_STOP(){ HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);} void MOTOR_UP(){ __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1,1); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);} void MOTOR_DOWN(){ __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1,400); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET);}

PID:

PID算法:

PID分为位置型和增量型

增量型即通过 u(k)-u(k-1) 从而得出式子:

公式的第一部门是比例式 是为了让值按必然比例到达目的值;

第二部门是积分值,正值,在计算的过程中往往会遭到情况等一些其他因素的影响,招致值不克不及抵达目的值;

第三部门是微分值,凡是是负值,后一次误差值往往小于前一次误差值,目标是为了避免值增加过大,凡是起一个障碍的感化;

stm32做PID算法控制减速直流电机  第25张

PID代码:

#include "pid.h"#include "tim.h"#include "main.h"#include "math.h"#include "i2c.h"#include "oled.h" unsigned int MotorSpeed; //È«¾Ö±äÁ¿£¬µç»úµ±Ç°×ªËÙint SpeedTarget = 750; //Ä¿±êתËÙint MotorOutput; //µç»úÊä³ö //1.ÀûÓÃTIM2¼ÆËãµç»úתËÙ void GetMotorSpeed(void){// int CaptureNumber = (short)__HAL_TIM_GET_COUNTER(&htim2); //HAL¿âº¯Êý¼ÆËãÂö³å´ÎÊý// // //µç»úתËÙת»»Speed=1sÄÚµÄÂö³åÊý/44(һȦ11¸öÐźţ¬4±¶Æµ·¨)/34¼õËÙ±È// int MotorSpeed=CaptureNumber*20/44/34*2*3.14*3;// OLED_ShowNum(40,0,MotorSpeed,4,16);// // __HAL_TIM_GET_COUNTER(&htim2) = 0; //¼ÆÊýÆ÷ÇåÁã int CaptureNumber = (short)__HAL_TIM_GET_COUNTER(&htim2); //??????? __HAL_TIM_GET_COUNTER(&htim2) = 0;// int Speed=CaptureNumber*5/44/34*2*3.14*3; int Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2); if(Direction == 1) { CaptureNumber -= 65535; } MotorSpeed=CaptureNumber; OLED_ShowNum(40,0,MotorSpeed,4,16); HAL_Delay(100); OLED_CLS();// __HAL_TIM_GET_COUNTER(&htim2) = 0;} //2.ÔöÁ¿Ê½PID¿ØÖÆÆ÷£¨PID³£¼û·ÖΪλÖÃPIDºÍÔöÁ¿Ê½PID£© int Error_Last,Error_Prev; //ÉÏ´ÎÎó²î£¬ÉÏÉÏ´ÎÎó²îint Pwm_add,Pwm; //PWMÔöÁ¿,PWMÕ¼¿Õ±È int Kp = 5, Ki = 3, Kd = 1;//PIDË㷨ϵÊý£¬¸¡µãÀàÐÍ£¬Ð¾Æ¬¼ÆËãÄÜÁ¦Ò»°ãʱ½¨ÒéÕûÐÍ£¬»òÕß*1024 int SpeedInnerControl(int Speed,int Target) //ËÙ¶ÈÄÚ»·¿ØÖÆ{ int Error = Target - Speed; //Îó²î = Ä¿±êËÙ¶È - ʵ¼ÊËÙ¶È Pwm_add = Kp * (Error - Error_Last) + //±ÈÀý Ki * Error + //»ý·Ö Kd * (Error - 2.0f * Error_Last + Error_Prev); //΢·Ö Pwm += Pwm_add; //Êä³öÁ¿=ԭʼÁ¿+ÔöÁ¿ Error_Prev = Error_Last; //±£´æÉÏÉÏ´ÎÎó²î Error_Last = Error; //±£´æÉÏ´ÎÎó²î if(Pwm > 4999) Pwm = 3000; //ÏÞÖÆÉÏÏÂÏÞ£¬·ÀÖ¹PWM³¬³öÁ¿³Ì if(Pwm <-4999) Pwm =-3000; return Pwm; //·µ»ØÊä³öÖµ} //3.µç»úתËÙÓë·½ÏòµÄº¯Êý£¨PID¿ØÖÆ£© void SetMotorVoltageAndDirection(int Pwm){ if(Pwm < 0) //Èç¹ûPWMСÓÚ0 { HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET); Pwm = (-Pwm); //PWMÖ»ÄÜÈ¡ÕýÖµ£¬Èç¹ûΪ¸ºÊý£¬Ö±½ÓÈ¡·´ __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, Pwm); //PWMµ÷ËÙ } else { HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,GPIO_PIN_SET); __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, Pwm); //PWMµ÷ËÙ }} void ModePID(){ GetMotorSpeed(); MotorOutput = SpeedInnerControl(MotorSpeed,SpeedTarget); SetMotorVoltageAndDirection(MotorOutput);}

主函数代码:

while (1) { switch(flag) { case(1):MOTOR_GO();break; case(2):MOTOR_BACK();break; case(3):MOTOR_STOP();break; case(4):MOTOR_UP();break; case(5):ModePID();break; default:break; } /* USER CODE END WHILE */ if(flag != 5) { int CaptureNumber = (short)__HAL_TIM_GET_COUNTER(&htim2); //??????? __HAL_TIM_GET_COUNTER(&htim2) = 0;// int Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2); //µç»úתËÙת»»Speed=1sÄÚµÄÂö³åÊý/44(һȦ11¸öÐźţ¬4±¶Æµ·¨)/34¼õËÙ±È// int Speed=CaptureNumber*5/44/34*2*3.14*3; int Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2); if(Direction == 1) { CaptureNumber -= 65535; } int Speed=CaptureNumber; OLED_ShowNum(40,0,Speed,5,16); HAL_Delay(100); OLED_CLS(); } int Direction = __HAL_TIM_IS_TIM_COUNTING_DOWN(&htim2); OLED_ShowCN_STR(0,0,0,3);// OLED_ShowNum(40,0,Speed,4,16); OLED_ShowStr(90,0,"cm/s",2); OLED_ShowCN_STR(0,3,3,2); if(Direction==0) { OLED_ShowCN_STR(40,3,5,2); } if(Direction==1) { OLED_ShowCN_STR(40,3,7,2); } // HAL_Delay(1000);// OLED_CLS(); /* USER CODE BEGIN 3 */ }

蓝牙APP源代码以及手艺论文:链接:https://pan.baidu.com/s/1-rbicxuyLVCq6rglCWcJTg 提取码:huzm