小车已经吃灰了好久,之前也没学过STM32,就从这里开始学习吧(小白写的东西简单大家理解一下,可能有借鉴其他网友的,但每一个都是自己实践过可以才发上来的)
目录
基础实验部分
一.小车的开箱以及遇到的问题(已更新)
高级实验部分
五.实现小车自主避障
六.实现小车利用线性CCD巡线
七.实现体感控制
八.撰写APP实现对小车的数据和状态进行监控
小车已经吃灰了好久,之前也没学过STM32,就从这里开始学习吧(小白写的东西简单大家理解一下,可能有借鉴其他网友的,但每一个都是自己实践过可以才发上来的)
目录
基础实验部分
一.小车的开箱以及遇到的问题(已更新)
高级实验部分
五.实现小车自主避障
六.实现小车利用线性CCD巡线
七.实现体感控制
八.撰写APP实现对小车的数据和状态进行监控
一.小车的开箱以及遇到的问题
开箱,太久了我的箱都不见了,小车的安装也是满简单的,安装时只要注意电池放的方向还有电机线的方向就行的(放对方向就没有必要去剪掉扎带了,懒人就是这样...)


安装完了之后打开开关就可以正常使用了,默认带的程序效果已经不错了
可惜在买了之后的一段时间吃灰之后,小车就出现问题了,开启时小车只能对一边的倾斜作出调整,倾向另外一边时没有任何的输出调整(已经是两次了,第一次的卖家帮忙弄好的,卖家人好),第二次就知道原因了,主控芯片的引脚虚焊了,当向下轻压芯片时小车能够正常两边调整,好吧,拿个电烙铁焊一下就好了,小问题(就是图中的st芯片)

效果如下视频:
下面就开始进入学习了
二.建立一个工程
由于是看着STM32自学笔记建立工程的,这里就按照他的方法吧
(1)先从网上下载ST公司的STM32固件库STM32f10x_fw_archive.rar然后解压
(2)新建6个文件夹分别为boot、library、src、obj、list、interrupt,将对应的文件放入到对应的文件夹中,如下目录结构:
(3)新建工程和选择芯片型号...(楼主比较懒所以就简单带过,重点说下自己在建立中遇到的问题把)
建立过程中记得添加路径,不然会找不到库文件(includes paths选项右边的省略号那里)

添加完之后应该如下

最好把Define那里写入STM32F10X_HD,USE_STDPERIPH_DRIVER(好像不加有很多问题后面)

有比楼主懒的那就下载分享的那个文件把,都拉好了STM32_FW.rar

三.点亮一个LED灯
查看原理图可知小车上有两个led灯,红灯是电源灯,蓝灯是工作灯,其接在PB8上,也就是GPIOB的第八个管脚上(是不是画反了!)

下面就直接看程序把LED点亮.rar需要下载的在这里
效果如下
#include "stm32f10x_lib.h"
void GPIO_Configuration(void);
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//ʹÄÜGPIOB
GPIO_Configuration();//GPIO定义
GPIO_ResetBits(GPIOB,GPIO_Pin_8);//拉低GPIO_Pin_8
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//选择引脚
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;//设置速度
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;//输出模式
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
四.LED灯利用systick定时器的延时闪烁
这是一个24位的系统节拍定时器system tick timer,SysTick,具有自动重载和溢出中断功能,所有基于Cortex_M3处理器的微控制器都可以由这个定时器获得一定的时间间隔。Systick就是一个定时器而已,只是它放在了NVIC中,主要的目的是为了给操作系统提供一个硬件上的中断(号称滴答中断)。代码下载闪烁LED.rar
上面的就是视频效果
直接看代码吧
delay.c
#include "stm32f10x_systick.h"
static u8 fac_us=0;//微秒
static u16 fac_ms=0;//毫秒
void delay_init(u8 SYSCLK) //初始化延时函数
{
SysTick->CTRL&=0xfffffffb;//bit2清0,选择外部时钟 HCLK/8
fac_us=SYSCLK/8;
fac_ms=(u16)fac_us*1000;
}
void delay_ms(u16 nms) //毫秒的延时
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms;
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL=0x01 ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达 SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us;
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL=0x01 ; //开始倒数
do
{
temp=SysTick->CTRL;
}
while(temp&0x01&&!(temp&(1<<16)));//等待时间到达 SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
delay.h
#include "stm32f10x_type.h" #ifndef __DELAY_H #define __DELAY_H void delay_init(u8 SYSCLK); void delay_ms(u16 nms); void delay_us(u32 nus); void get_ms(unsigned long *count); #endif
main.c
#include "stm32f10x_lib.h"
#include "delay.h"
void GPIO_Configuration(void);
int main(void)
{
delay_init(72);//初始化延时函数
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能
GPIO_Configuration();
while(1)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_8);//点亮
delay_ms(50);
GPIO_SetBits(GPIOB,GPIO_Pin_8);//熄灭
delay_ms(50);
}
}
void GPIO_Configuration(void)//GPIO定义
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
} 五.按键控制LED灯的亮灭
按键如原理图,PB5口与按键连接,读取PB5的电平就可以知道按键的状态

按键延时程序主要就先检测按键是否按下,接着延时消抖,再次检测按键是否按下,如果真的按下就返回相应的值,注意松手检测。效果如下:
好吧,上代码按键.rar delay.c同上,就不再赘述
#include "stm32f10x_lib.h"
#include "stm32f10x_systick.h"
#include "delay.h"
#define KEY0 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)//宏定义读取GPIOB5的电平
int i,j;
void KEY_Scan(void);//按键扫描声明
void GPIO_Configuration(void);
int main(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//ʹÄÜPORTB,PORTEʱÖÓ
delay_init(72);//初始化延时函数
GPIO_Configuration();//GPIO的配置
while(1)
{
KEY_Scan();//键盘扫描
if(i==1)
GPIO_WriteBit(GPIOB,GPIO_Pin_8,(BitAction)(1-(GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_8))));//翻转电平
}
}
void KEY_Scan(void)
{
if(KEY0==0)
{
delay_ms(10);//延时消抖
j=0;
if(KEY0==0)
{
//i=1;
while(j<50&&(!KEY0))//松手检测
{
delay_ms(1);
j++;
}
i=1;
}
} else
i=0;
}
void GPIO_Configuration(void)//
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_InitStructure.GPIO_Mode =GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
结束按键实验
六.采用PWM驱动电机
在实验之前,我们先来了解一下小车驱动的相关知识吧。
对于电机的转速调整,我们是采用脉宽调制(PWM)办法,控制电机的时候,电源并非连续地向电机供电,而是在一个特定的频率下以方波脉冲的形式提供电能。不同占空比的方波信号能对电机起到调速作用,这是因为电机实际上是一个大电感,它有阻碍输入电流和电压突变的能力,因此脉冲输入信号被平均分配到作用时间上,这样,改变在输入方波的占空比就能改变加在电机两端的电压大小,从而改变了转速。
而我们单片机CPU的IO引脚无法提供足够的电流,所以需要通过一个驱动电路实现对直流电机的驱动。小车采用的是TB6612。驱动电路的核心是一组桥式开关,通过控制四个开关的导通与否决定电机是正转还是反转还是制动。

TB6612FNG这款驱动芯片的真值表如下:

该器件工作时STBY引脚置为高电平;IN1和IN2不变,调整PWM引脚的输入信号可进行电机单向速度控制;置PWM引脚为高电平,并调整IN1和IN2的输入信号可进行电机双向速度控制。
那么,程序中该如何设置呢?代码中通过TIM3作为电机的PWM源信号产生,并且都工作早PWM1模式下,而在PWM1模式下,变化的计数器不断与CCRy进行比较。假设计数器采用加计数方式,当计数器的值TIMx_CNT小于TIMx_CCRy时,PWM信号保持高电平。当TIMx_CNT不断增加,直到大于TIMx_CCRy时,PWM变成低电平。TIMx_CNT继续增加,当达到TIMx_ARR预设的值后,复位返回0值。
简单地理解就是,TIM3->ARR决定了PWM信号的周期(TIM3->ARR=arr;),TIM3->CCR4和TIM3->CCR3决定了PWM信号的占空比(在我的代码中是这样的)电机驱动.rar
代码如下:
main.c
#include "main.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
void SystemInit (void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set HSION bit */
RCC->CR |= (unsigned int)0x00000001;
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
}
void MiniBalance_Motor_Init(void)
{
RCC->APB2ENR|=1<<3; //PORTB使能输出 GPIOB->CRH&=0X0000FFFF; //PORTB12 13 14 15推挽输出
GPIOB->CRH|=0X22220000; //PORTB12 13 14 15推挽输出
}
void MiniBalance_PWM_Init(u16 arr,u16 psc)
{
MiniBalance_Motor_Init(); //初始化驱动电机所需IO
RCC->APB1ENR|=1<<1; //TIM3使能 RCC->APB2ENR|=1<<3; //PORTB时钟使能 GPIOB->CRL&=0XFFFFFF00; //PORTB0 1复用输出
GPIOB->CRL|=0X000000BB; //PORTB0 1复用输出
TIM3->ARR=arr;//计数器自动重装值
TIM3->PSC=psc;//预分频器不分频
TIM3->CCMR2|=6<<12;//CH4 PWM1模式 TIM3->CCMR2|=6<<4; //CH3 PWM1模式 TIM3->CCMR2|=1<<11;//CH4预装载使能 TIM3->CCMR2|=1<<3; //CH3预装载使能 TIM3->CCER|=1<<12; //CH4输出使能 TIM3->CCER|=1<<8; //CH3输出使能 TIM3->CR1=0x8000; //ARPE使能
TIM3->CR1|=0x01; //使能定时器3
}
int main(void)
{
SysTick->CTRL&=0xfffffffb;//bit2清空,选择外部时钟HCLK/8
SystemInit();
MiniBalance_PWM_Init(3599,0);
while(1)
{
GPIOB->ODR &= ~(1<<8); PWMA = 3000; PWMB = 3000; GPIO_ResetBits(GPIOB,GPIO_Pin_15);//AIN2=0 GPIO_SetBits(GPIOB,GPIO_Pin_14);//AIN1=1 逆时针 GPIO_ResetBits(GPIOB,GPIO_Pin_13);//BIN1=0 GPIO_SetBits(GPIOB,GPIO_Pin_12);//BIN2=1 顺时针 } }
main.h
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C #define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C #define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C #define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C #define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C #define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C #define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C #define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808 #define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08 #define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008 #define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408 #define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808 #define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08 #define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08 //IO操作 #define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出 #define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入 #define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) #define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) #define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) #define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) #define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) #define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) #define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) #define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) #define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) #define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) #define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) #define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) #define PWMA TIM3->CCR4 #define AIN2 PBout(15) #define AIN1 PBout(14) #define BIN1 PBout(13) #define BIN2 PBout(12) #define PWMB TIM3->CCR3
电机驱动结束
七.USART的通讯
当你需要设计一个上位机是串口通信必然是最基本的组件,STM32固件库为串口通信的操作提供了很多有用的函数,使得我们在使用串口时不必关注底层硬件的操作,使用相关函数即可,下面介绍串口操作的要点。串口发送.rar
从原理图可以看出串口1连接PA9和PA10

在代码中先对串口的IO口配置和波特率等设置
void usart1_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//选择PA9为复用输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//PA10为浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = 115200; //波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长设置
USART_InitStructure.USART_StopBits = USART_StopBits_1;//1位的停止位
USART_InitStructure.USART_Parity = USART_Parity_No ;//无奇偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不启用硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //使能发送和接受功能
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
如果要使用printf函数打印信息,需要加fputc函数,就需要对printf函数重定向到串口。
int fputc(int ch, FILE *f)
{
USART1->DR=(u8)ch;
while((USART1->SR&0X40)==0);
return ch;
}
main函数中的调用
int main(void)
{
int i=0;
usart1_init();
while(1)
{
printf("\r\nEEPW-liushidesuiyue\r\n");
for(i=0;i<30000;i++); //短暂延时,保证发送完全
}
}
在options for target中一定要勾选use Microlib,否则即使程序代码是对的也不会像串口发送消息。

设置完下载进去就可以了

视频如下
串口实验结束
八.编码器读取电机的转速
直流电机编码器的作用,主要是测定电机的速度,为控制器提供反馈信号。是半闭环控制的检测元件。编码器读取.rar

从原理图中可以看出,编码器用到了单片机的PA0、PA1、PB6、PB7接口,还用定时器1,2,4,定时器1用来进行50ms的中断任务执行,定时器2和4分别对编码器1和2产生溢出中断,完成对编码器脉冲的计数。代码主要包括oled屏的显示和定时器、编码器的设置。
效果如下

先上定时器的设置:
timer.c
#include "timer.h"
#include "math.h"
void TIM2_IRQHandler(void)//编码器读取中断
{
if(TIM2->SR&0X0001)//溢出中断
{
}
TIM2->SR&=~(1<<0);// 清除中断标志位 } void TIM4_IRQHandler(void)//编码器读取中断 { u16 tsr; tsr=TIM4->SR;
if(tsr&0X0001)
{
}
TIM4->SR&=~(1<<0); } void Encoder_Init2(void)//编码器初始化 { /* TIM2 clock source enable */ RCC->APB1ENR|=1<<0; //TIM2ʱÖÓʹÄÜ /* Enable GPIOA, clock */ RCC->APB2ENR|=1<<2; //ʹÄÜPORTAʱÖÓ /* Configure PA.00,01 as encoder input */ GPIOA->CRL&=0XFFFFFFF0;//PA0
GPIOA->CRL|=0X00000004;
GPIOA->CRL&=0XFFFFFF0F;//PA1
GPIOA->CRL|=0X00000040;
/* Enable the TIM2 Update Interrupt */
TIM2->DIER|=1<<0; TIM2->DIER|=1<<6; MY_NVIC_Init(1,3,TIM2_IRQChannel,1); /* Timer configuration in Encoder mode */ TIM2->PSC = 0x0;
TIM2->ARR = ENCODER_TIM_PERIOD-1;
TIM2->CR1 &=~(3<<8); TIM2->CR1 &=~(3<<5); TIM2->CCMR1 |= 1<<0; //CC1S='01' TIM2->CCMR1 |= 1<<8; //CC2S='01' TIM2->CCER &= ~(1<<1); //CC1P='0' TIM2->CCER &= ~(1<<5); //CC2P='0' TIM2->CCMR1 |= 3<<4; // IC1F='1000' TIM2->SMCR |= 3<<0; //SMS='011' TIM2->CNT = COUNTER_RESET;
TIM2->CR1 |= 0x01;
}
void Encoder_Init(void)//编码器初始化
{
/* TIM4 clock source enable */
RCC->APB1ENR|=1<<2; //TIM3使能 /* Enable GPIOB, clock */ RCC->APB2ENR|=1<<3; /* Configure PB.06,07 as encoder input */ GPIOB->CRL&=0XF0FFFFFF;//PB6
GPIOB->CRL|=0X08000000;
GPIOB->CRL&=0X0FFFFFFF;//PB7
GPIOB->CRL|=0X40000000;
/* Enable the TIM3 Update Interrupt */
TIM4->DIER|=1<<0; TIM4->DIER|=1<<6; MY_NVIC_Init(1,3,TIM4_IRQChannel,1); /* Timer configuration in Encoder mode */ TIM4->PSC = 0x0;
TIM4->ARR = ENCODER_TIM_PERIOD-1;
TIM4->CR1 &=~(3<<8); TIM4->CR1 &=~(3<<5); TIM4->CCMR1 |= 1<<0; //CC1S='01' IC1FP1Ó³Éäµ½TI1 TIM4->CCMR1 |= 1<<8; //CC2S='01' IC2FP2Ó³Éäµ½TI2 TIM4->CCER &= ~(1<<1); //CC1P='0' TIM4->CCER &= ~(1<<5); //CC2P='0' TIM4->CCMR1 |= 3<<4; // IC1F='1000' TIM4->SMCR |= 3<<0; //SMS='011' TIM4->CNT = COUNTER_RESET;
TIM4->CR1 |= 0x01;
}
//定时中断初始化
void Timer1_Init(u16 arr,u16 psc)
{
RCC->APB2ENR|=1<<11;//TIM2时钟使能 TIM1->ARR=arr; //自动重装初值
TIM1->PSC=psc; //
TIM1->DIER|=1<<0; //允许更新中断 TIM1->DIER|=1<<6; //允许触发中断 TIM1->CR1|=0x01;
MY_NVIC_Init(1,3,TIM1_UP_IRQChannel,1);
}
void MiniBalance_PWM_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<1; //TIM3ʱÖÓʹÄÜ RCC->APB2ENR|=1<<3; //PORTBʱÖÓʹÄÜ GPIOB->CRL&=0XFFFFFF00; //PORTB0 1¸´ÓÃÊä³ö
GPIOB->CRL|=0X000000BB; //PORTB0 1¸´ÓÃÊä³ö
GPIOB->CRH&=0X0000FFFF; //PORTB12 13 14 15ÍÆÍìÊä³ö
GPIOB->CRH|=0X22220000; //PORTB12 13 14 15ÍÆÍìÊä³ö
TIM3->ARR=arr;//É趨¼ÆÊýÆ÷×Ô¶¯ÖØ×°Öµ
TIM3->PSC=psc;//Ô¤·ÖƵÆ÷²»·ÖƵ
TIM3->CCMR2|=6<<12;//CH4 PWM2ģʽ TIM3->CCMR2|=6<<4; //CH3 PWM2ģʽ TIM3->CCMR2|=1<<11;//CH4Ô¤×°ÔØÊ¹ÄÜ TIM3->CCMR2|=1<<3; //CH3Ô¤×°ÔØÊ¹ÄÜ TIM3->CCER|=1<<12; //CH4Êä³öʹÄÜ TIM3->CCER|=1<<8; TIM3->CR1=0x8000;
TIM3->CR1|=0x01;
}
//NVIC初始化
void MY_NVIC_Init(u8 NVIC_PreemptionPriority,u8 NVIC_SubPriority,u8 NVIC_Channel,u8 NVIC_Group)
{
u32 temp;
u8 IPROFFSET=NVIC_Channel%4;//ÔÚ×éÄ򵀮«ÒÆ
IPROFFSET=IPROFFSET*8+4; //µÃµ½Æ«ÒƵÄÈ·ÇÐλÖÃ
MY_NVIC_PriorityGroupConfig(NVIC_Group);//ÉèÖ÷Ö×é
temp=NVIC_PreemptionPriority<<(4-NVIC_Group); temp|=NVIC_SubPriority&(0x0f>>NVIC_Group);
temp&=0xf;//È¡µÍËÄλ
if(NVIC_Channel<32)NVIC->ISER[0]|=1AIRCR;
temp&=0X0000F8FF;
temp|=0X05FA0000;
temp|=temp1;
SCB->AIRCR=temp;
}
通过该函数在5ms的中断服务中读取编码器的值
void TIM1_UP_TIM16_IRQHandler(void)
{
if(TIM1->SR&0X0001)//5ms定时中断
{
TIM1->SR&=~(1<<0); //清除定时器1的中断标志位 readEncoder(); //读取编码器的值 }
void readEncoder(void)
{
u16 Encoder_L,Encoder_R; //左右编码器的脉冲计数
Encoder_R = TIM4 -> CNT; //获取编码器1的计数
TIM4 -> CNT=0; //计数器清零
Encoder_L= TIM2 -> CNT; //获取编码器2的计数
TIM2 -> CNT=0; //计数器清零
if(Encoder_L>32768) Encoder_Left=Encoder_L-65000; else Encoder_Left=Encoder_L;
if(Encoder_R>32768) Encoder_Right=Encoder_R-65000; else Encoder_Right=Encoder_R;
Encoder_Left=-Encoder_Left;
}
主要就是这几个函数,注意添加编码器的读取中断TIM2_IRQHandler()和TIM4_IRQHandler(),原先忘了添加一直在那里读取不到编码器的计数好久....
视频效果
好了,编码器读取的实验就结束了
九.无线通讯实验
蓝牙连接的是串口3,如图

蓝牙在串口接受中断中:
void USART3_IRQHandler(void)
{
if(USART3->SR&(1<<5))//接受中断
{
static int uart_receive=0;//蓝牙接受相关的变量
uart_receive=USART3->DR;
if(uart_receive<10) mode_data[0]=uart_receive;
if((mode_data[0]==six_data_2[0]
&&mode_data[1]==six_data_2[1]
&&mode_data[2]==six_data_2[2]
&&mode_data[3]==six_data_2[3])
||(mode_data[0]==six_data_1[0]
&&mode_data[1]==six_data_1[1]
&&mode_data[2]==six_data_1[2]
&&mode_data[3]==six_data_1[3]))
{
Flag_Stop=!Flag_Stop;
mode_data[0]=0; mode_data[1]=0; mode_data[2]=0; mode_data[3]=0;
}
if(uart_receive==0x00) Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////刹车
if(uart_receive==0x01) Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////前
if(uart_receive==0x05) Flag_Qian=0,Flag_Hou=1,Flag_Left=0,Flag_Right=0;//////////////后
else if(uart_receive==0x02||uart_receive==0x03||uart_receive==0x04)
Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=1;
else if(uart_receive==0x06||uart_receive==0x07||uart_receive==0x08)
Flag_Qian=0,Flag_Hou=0,Flag_Left=1,Flag_Right=0;
mode_data[7]=mode_data[6];
mode_data[6]=mode_data[5];
mode_data[5]=mode_data[4];
mode_data[4]=mode_data[3];
mode_data[3]=mode_data[2];
mode_data[2]=mode_data[1];
mode_data[1]=mode_data[0];
}
}
从APP发送数据,串口接收发送中断,对接收到的数据进行匹配并进行相应的动作处理。
| 有奖活动 | |
|---|---|
| 硬核工程师专属补给计划——填盲盒 | |
| “我踩过的那些坑”主题活动——第002期 | |
| 【EEPW电子工程师创研计划】技术变现通道已开启~ | |
| 发原创文章 【每月瓜分千元赏金 凭实力攒钱买好礼~】 | |
| 【EEPW在线】E起听工程师的声音! | |
| 高校联络员开始招募啦!有惊喜!! | |
| 【工程师专属福利】每天30秒,积分轻松拿!EEPW宠粉打卡计划启动! | |
| 送您一块开发板,2025年“我要开发板活动”又开始了! | |
我要赚赏金打赏帖 |
|
|---|---|
| Chaos-nano:专为低资源单片机设计的轻量级协作式异步操作系统(ATMEGA328P轻量级操作系统)—— 详细介绍被打赏¥16元 | |
| FPGA配置被打赏¥10元 | |
| Chaos-nano协作式异步操作系统:赋能MicrochipAVR8位单片机的革新之路被打赏¥15元 | |
| 基于esp32开发时串口工具的注意点被打赏¥24元 | |
| 基于FireBeetle2ESP32-C5开发板的舵机控制被打赏¥20元 | |
| 【分享开发笔记,赚取电动螺丝刀】MAX78000开发板制作的电子相册被打赏¥32元 | |
| 基于FireBeetle2ESP32-C5开发板的超声波测距及显示被打赏¥21元 | |
| FireBeetle2ESP32-C5上RTC电子时钟的实现被打赏¥25元 | |
| 【分享开发笔记,赚取电动螺丝刀】MAX78000开发板读取SD卡被打赏¥23元 | |
| 【S32K3XX】Standby RAM 重启后数据异常问题调查被打赏¥38元 | |