开发板 正点原子 stm32F103ZET6
#define _encoder_H_
#ifndef _encoder_H_
#define _encoder_H_
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#define ENCODER_TIM_PERIOD (u16)(65535) //不可大于65535 因为F103的定时器是16位的。
typedef struct bianmadianji
{
float coderA;
float coderB;
u8 mode; //正反转状态
}G_ENCODER;
extern G_ENCODER g_ENCODER;
void Encoder_Init_TIM2(void);
void Encoder_Init_TIM3(void);
float Read_EncoderA(void); //读取编码电机A 单位时间内的脉冲数
float Read_EncoderB(void); //读取编码电机B 单位时间内的脉冲数
void TIM2_IRQHandler(void); //cnt 计数满,清除
void TIM3_IRQHandler(void);
#endif
encoder.c
#include "encoder.h"
G_ENCODER g_ENCODER={0,0,0};
/**************************************************************************
* 函数功能:把TIM2初始化为编码器接口模式
* 端口配置: PA_15 ; PB_3
* 入口参数:无
* 返 回 值:无
**************************************************************************/
void Encoder_Init_TIM2(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能定时器2的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);//使能PA PB端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //重映射
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //端口配置 PA15
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //端口配置 PB3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//边沿计数模式
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //初始化定时器2
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3
TIM_ICStructInit(&TIM_ICInitStructure); //把TIM_ICInitStruct 中的每一个参数按缺省值填入
TIM_ICInitStructure.TIM_ICFilter = 10; //设置滤波器长度
TIM_ICInit(TIM2, &TIM_ICInitStructure);//根据 TIM_ICInitStruct 的参数初始化外设 TIMx
TIM_ClearFlag(TIM2, TIM_FLAG_Update);//清除TIM的更新标志位
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);//使能定时器中断
TIM_SetCounter(TIM2,0); //计数初值设定
TIM_Cmd(TIM2, ENABLE); //使能定时器2
}
/**************************************************************************
函数功能:把TIM3初始化为编码器接口模式
端口配置: PA6 PA7
入口参数:无
返回 值:无
**************************************************************************/
void Encoder_Init_TIM3(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);//使能定时器3的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能PA端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //端口配置 PA6 PA7
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Prescaler = 0x0; // 预分频器
TIM_TimeBaseStructure.TIM_Period = ENCODER_TIM_PERIOD; //设定计数器自动重装值
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频:不分频
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//边沿计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化定时器3
TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12,TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);//使用编码器模式3(TIM_ICPolarity_Rising或者TIM_ICPolarity_Falling效果相同,都是4倍频)
TIM_ICStructInit(&TIM_ICInitStructure); //把TIM_ICInitStruct 中的每一个参数按缺省值填入
TIM_ICInitStructure.TIM_ICFilter = 10; //设置滤波器长度
TIM_ICInit(TIM3, &TIM_ICInitStructure);//根据 TIM_ICInitStruct 的参数初始化外设 TIMx
TIM_ClearFlag(TIM3, TIM_FLAG_Update);//清除TIM的更新标志位
TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);//使能定时器中断
TIM_SetCounter(TIM3,0);//计数初值设定
TIM_Cmd(TIM3, ENABLE); //使能定时器
}
/**************************************************************************
函数功能:单位时间读取编码器A计数
入口参数:无
返回 值:计数值
**************************************************************************/
float Read_EncoderA(void)
{
g_ENCODER.encoderA= (short)TIM2 -> CNT; //该寄存器储存了 编码器的位置信息
TIM2->CNT=0; //读取之后 编码计数--清零--,不清零请注释掉
return g_ENCODER.encoderA;
}
/**************************************************************************
函数功能:单位时间读取编码器B计数
入口参数:无
返回 值:计数值
**************************************************************************/
float Read_EncoderB(void)
{
g_ENCODER.encoderB= (short)TIM3 -> CNT; //该寄存器储存了 编码器的位置信息,
TIM3->CNT = 0 ; //读取之后 编码计数--清零--,不清零请注释掉
return g_ENCODER.encoderB;
}
/**************************************************************************
* 函数功能:TIM2中断服务函数
*
* 入口参数:无
*
* 返 回 值:无
**************************************************************************/
void TIM2_IRQHandler(void)
{
if(TIM2->SR& 0X0001)//溢出中断
{
}
TIM2->SR&=~(1<<0);//清除中断标志位
}
/**************************************************************************
* 函数功能:TIM3中断服务函数
*
* 入口参数:无
*
* 返 回 值:无
**************************************************************************/
void TIM3_IRQHandler(void)
{
if(TIM3->SR&0X0001)//溢出中断
{
}
TIM3->SR&=~(1<<0);//清除中断标志位
}
pwm_motor.h
#ifndef _pwm_motor_H
#define _pwm_motor_H
#include "sys.h"
#include "stdio.h"
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "encoder.h"
typedef struct pwm_motor_data
{
uint16_t CCR1_Val ;
uint16_t CCR2_Val ;
uint16_t CCR3_Val ;
uint16_t CCR4_Val ;
float speedA;
float speedB;
uint16_t arr ; //10ms秒读取一次
uint16_t psc ;
}G_PWM_MOTOR;
extern G_PWM_MOTOR g_PWM_MOTOR;
void Timer_5_pwm_init();
void MOTOR_encoder( uint16_t ccr1,uint16_t ccr2, uint16_t ccr3, uint16_t ccr4);
#endif // !1
pwm_motor.c
#include "pwm_motor.h"
#include "sys.h"
uint16_t arr_5 = 100; //10ms秒读取一次
uint16_t psc_5 = 7200-1;
G_PWM_MOTOR g_PWM_MOTOR={
.arr= 100-1,
.psc= 7200-1,
// 占空比配置 有效占比/高电平占比 n/100 %
.CCR1_Val=20,
.CCR2_Val=20,
.CCR3_Val=20,
.CCR4_Val=20
};
void Timer_5_pwm_init() //arr :自动重装值 psc :时钟预分频数
{
//1) TIM5 时钟使能。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);// 时钟使能
//2) 初始化定时器参数,设置自动重装值, 分频系数,计数方式等。
TIM_TimeBaseInitTypeDef Timer_5_initstruct;
Timer_5_initstruct.TIM_ClockDivision=TIM_CKD_DIV1; //时钟分频银子
Timer_5_initstruct.TIM_CounterMode=TIM_CounterMode_Up;//计数方式 上下....
Timer_5_initstruct.TIM_Period= arr_5;//自动重装载时钟周期
Timer_5_initstruct.TIM_Prescaler= psc_5;//时钟分频银子
//Timer_5_initstruct.TIM_RepetitionCounter
TIM_TimeBaseInit( TIM5 , &Timer_5_initstruct);
//3) 设置 TIM5_DIER 允许更新中断。
TIM_ITConfig(TIM5, TIM_IT_Update, ENABLE);
//4) TIM5 中断优先级设置。
NVIC_InitTypeDef NVIC_init_struct;
NVIC_init_struct.NVIC_IRQChannel= TIM5_IRQn; //中断通道
NVIC_init_struct.NVIC_IRQChannelPreemptionPriority=0; //抢占优先级
NVIC_init_struct.NVIC_IRQChannelSubPriority=1; //相应
NVIC_init_struct.NVIC_IRQChannelCmd=ENABLE;//使能中断通道
NVIC_Init(&NVIC_init_struct); //初始化
/*--------------------pwm输出结构体初始化-------------------*/
TIM_OCInitTypeDef TIM_OCInitStructure;
// 配置为PWM模式1
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
// 输出使能
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
// 输出通道电平极性配置
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
//pwm输出通道 1
TIM_OCInitStructure.TIM_Pulse = g_PWM_MOTOR.CCR1_Val;
TIM_OC1Init(TIM5, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable);
// pwm输出通道 2
TIM_OCInitStructure.TIM_Pulse = g_PWM_MOTOR.CCR2_Val;
TIM_OC2Init(TIM5, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM5, TIM_OCPreload_Enable);
// pwm输出通道 3
TIM_OCInitStructure.TIM_Pulse = g_PWM_MOTOR.CCR3_Val;
TIM_OC3Init(TIM5, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM5, TIM_OCPreload_Enable);
// pwm输出通道 4
TIM_OCInitStructure.TIM_Pulse = g_PWM_MOTOR.CCR4_Val;
TIM_OC4Init(TIM5, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM5, TIM_OCPreload_Enable);
//5) TIM5 的使能 启动。
TIM_Cmd(TIM5, ENABLE);//使能相应 计时器
}
void MOTOR_encoder( uint16_t ccr1,uint16_t ccr2, uint16_t ccr3, uint16_t ccr4)
{
TIM_SetCompare1(TIM5, ccr1);
TIM_SetCompare2(TIM5, ccr2);
TIM_SetCompare3(TIM5, ccr3);
TIM_SetCompare4(TIM5, ccr4);
}
void TIM5_IRQHandler(void)
{
if(RESET!=TIM_GetITStatus(TIM5, TIM_IT_Update))
{
TIM_ClearITPendingBit(TIM5,TIM_IT_Update);//触发中断后 重新计时
Read_EncoderA(); //更新编码机 读取到的 10ms内的 脉冲数
Read_EncoderB();
// g_PWM_MOTOR.speedA = //知道了 10ms 的脉冲数,可以计算电机转速
// g_PWM_MOTOR.speedB =
printf("编码机A脉冲数:%.2f /10ms", g_ENCODER.coderA);
printf("编码机B脉冲数:%.2f /10ms", g_ENCODER.coderB);
}
}
main.c
#include "usart.h"
#include "delay.h"
#include "lcd.h"
#include "led.h"
#include "key.h"
#include "encoder.h"
#include "pwm_motor.h"
void init____(void)
{
delay_init(); LED_Init(); KEY_Init(); LCD_Init(); uart_init(115200);
Timer_5_pwm_init(); //电机pwm发生源初始化
Encoder_Init_TIM2();
Encoder_Init_TIM3();
}
int main(void)
{
//编码器数值的读取 以及串口打印
//在 pwm_motor.c文件内的 TIM5中断函数
u8 key_value = 0xff;
while(1)
{
key_value=KEY_Scan(0);
switch( key_value )
{
case KEY0_PRES: g_PWM_MOTOR.CCR1_Val-=20 ; break; //这里 只控制 TIM5 的 通道一输出的 pwm波 占空比 用作测试
case KEY1_PRES: g_PWM_MOTOR.CCR1_Val+=20 ; break;
case WKUP_PRES: g_PWM_MOTOR.CCR1_Val =100 ; break;
default : break;
}
if( g_PWM_MOTOR.CCR1_Val > 100 || g_PWM_MOTOR.CCR1_Val <0)
{
g_PWM_MOTOR.CCR1_Val = 0 ;
}
}
}