STM32端口模拟编码器输入

文章目录

  • 前言
  • 一、正交编码器是什么?
  • 二、使用步骤
  • 2.1开启时钟
  • 2.2配置编码器引脚 TIM3 CH1(PA6) CH2 (PA7)上拉输入
  • 2.3.初始化编码器时基
  • 2.4 初始化编码器输入
  • 2.5 配置编码器接口
  • 2.6 开启定时器
  • 2.7获取编码器数据
  • 三、参考程序
  • 四、测试结果
  • 4.1测试方法
  • 4.2串口输出结果
  • 总结

  • 前言

    提示:这里可以添加本文要记录的大概内容:

    项目需要:


    提示:以下是本篇文章正文内容,下面案例可供参考

    一、正交编码器是什么?


    在这里插入图片描述

    二、使用步骤

    2.1开启时钟

    	/*开启时钟*/
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
    

    2.2配置编码器引脚 TIM3 CH1(PA6) CH2 (PA7)上拉输入

    	/*GPIO初始化*/
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);	
    

    2.3.初始化编码器时基

    代码如下(示例):

    	/*时基单元初始化*/
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
    	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
    

    2.4 初始化编码器输入

    代码如下(示例):

    /*输入捕获初始化*/
    	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
    	TIM_ICStructInit(&TIM_ICInitStructure);							//结构体初始化,若结构体没有完整赋值
    																	//则最好执行此函数,给结构体所有成员都赋一个默认值
    																	//避免结构体初值不确定的问题
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
    	TIM_ICInitStructure.TIM_ICFilter = 0;							//输入滤波器参数,可以过滤信号抖动
    	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;				//选择配置定时器通道2
    	TIM_ICInitStructure.TIM_ICFilter = 0;							//输入滤波器参数,可以过滤信号抖动
    	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
    

    2.5 配置编码器接口

    	/*编码器接口配置*/
    	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
    																	//配置编码器模式以及两个输入通道是否反相
    																	//注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相
    																	//此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置
    

    2.6 开启定时器

    	/*TIM使能*/
    	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行
    

    2.7获取编码器数据

    /**
      * 函    数:获取编码器的增量值
      * 参    数:无
      * 返 回 值:自上此调用此函数后,编码器的增量值
      */
    int16_t Encoder_Get(void)
    {
    	/*使用Temp变量作为中继,目的是返回CNT后将其清零*/
    	int16_t Temp;
    	Temp = TIM_GetCounter(TIM3);
    	TIM_SetCounter(TIM3, 0);
    	return Temp;
    }
    

    三、参考程序

    #include "stm32f10x.h"
    #include "stdio.h"
    //全局
    
     GPIO_InitTypeDef GPIO_InitStruct;
     
     int x;
     
     
     /**
      * 函    数:编码器初始化
      * 参    数:无
      * 返 回 值:无
      */
    void Encoder_Init(void)
    {
    	/*开启时钟*/
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);			//开启TIM3的时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);			//开启GPIOA的时钟
    	
    	/*GPIO初始化*/
    	GPIO_InitTypeDef GPIO_InitStructure;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStructure);							//将PA6和PA7引脚初始化为上拉输入
    	
    	/*时基单元初始化*/
    	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//定义结构体变量
    	TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //时钟分频,选择不分频,此参数用于配置滤波器时钟,不影响时基单元功能
    	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式,选择向上计数
    	TIM_TimeBaseInitStructure.TIM_Period = 65536 - 1;               //计数周期,即ARR的值
    	TIM_TimeBaseInitStructure.TIM_Prescaler = 1 - 1;                //预分频器,即PSC的值
    	TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;            //重复计数器,高级定时器才会用到
    	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStructure);             //将结构体变量交给TIM_TimeBaseInit,配置TIM3的时基单元
    	
    	/*输入捕获初始化*/
    	TIM_ICInitTypeDef TIM_ICInitStructure;							//定义结构体变量
    	TIM_ICStructInit(&TIM_ICInitStructure);							//结构体初始化,若结构体没有完整赋值
    																	//则最好执行此函数,给结构体所有成员都赋一个默认值
    																	//避免结构体初值不确定的问题
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;				//选择配置定时器通道1
    	TIM_ICInitStructure.TIM_ICFilter = 0;							//输入滤波器参数,可以过滤信号抖动
    	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
    	TIM_ICInitStructure.TIM_Channel = TIM_Channel_2;				//选择配置定时器通道2
    	TIM_ICInitStructure.TIM_ICFilter = 0;							//输入滤波器参数,可以过滤信号抖动
    	TIM_ICInit(TIM3, &TIM_ICInitStructure);							//将结构体变量交给TIM_ICInit,配置TIM3的输入捕获通道
    	
    	/*编码器接口配置*/
    	TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
    																	//配置编码器模式以及两个输入通道是否反相
    																	//注意此时参数的Rising和Falling已经不代表上升沿和下降沿了,而是代表是否反相
    																	//此函数必须在输入捕获初始化之后进行,否则输入捕获的配置会覆盖此函数的部分配置
    	
    	/*TIM使能*/
    	TIM_Cmd(TIM3, ENABLE);			//使能TIM3,定时器开始运行
    }
    
    /**
      * 函    数:获取编码器的增量值
      * 参    数:无
      * 返 回 值:自上此调用此函数后,编码器的增量值
      */
    int16_t Encoder_Get(void)
    {
    	/*使用Temp变量作为中继,目的是返回CNT后将其清零*/
    	int16_t Temp;
    	Temp = TIM_GetCounter(TIM3);
    	TIM_SetCounter(TIM3, 0);
    	return Temp;
    }
    
    void usart1_init()
    {
    
    //PA9  TX  PA10 RX   USART1
    	
    	
    	GPIO_InitTypeDef GPIO_InitStruct;
    	USART_InitTypeDef USART_InitStruct;
    	
    	NVIC_InitTypeDef NVIC_InitStruct;
    	
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);//1.开时钟
    	
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9;//发送
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStruct);
    	
    	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10;//接收
    	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    	GPIO_Init(GPIOA, &GPIO_InitStruct);
    	
    	USART_InitStruct.USART_BaudRate=115200;
    	USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
    	USART_InitStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
    	USART_InitStruct.USART_Parity=USART_Parity_No;
    	USART_InitStruct.USART_StopBits=USART_StopBits_1;
    	USART_InitStruct.USART_WordLength=USART_WordLength_8b;
    	
    	USART_Init(USART1, &USART_InitStruct);//2.初始化串口 
    	
    	USART_Cmd(USART1, ENABLE);//3.是能串口
    	
    	USART_SendData(USART1, '4');
    	
    	while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)!=1);
    	
    	
    	USART_SendData(USART1, '1');
    		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)!=1);
    	
    	
    	USART_SendData(USART1, 0X41);
    		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)!=1);
    	USART_SendData(USART1, 41);
    		while(USART_GetFlagStatus(USART1, USART_FLAG_TXE)!=1);
    	
    	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE );// 4.接受完成中断
    	
    	
    	 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 5.配置中断分组
    	 NVIC_InitStruct.NVIC_IRQChannel=USART1_IRQn;
    	 NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    	 NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
    	 NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;	 
    	 
       NVIC_Init(&NVIC_InitStruct);//配置中断优先级
    	
    
    }
    
    int fputc(int ch,FILE *f)
    {
    
    	   USART_SendData(USART1, (u8)ch);
    	   while(!USART_GetFlagStatus(USART1, USART_FLAG_TXE));
    	   return ch;
    }
    
    
    void delay(u16 ms)
    {
    
    		u16 i,j;
    	for(i=0;i<ms;i++)
    	for(j=0;j<1000;j++);
    }
     
    
    int main()
    {
    
    //局部	
    	// 库函数开启GPIO时钟
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB, ENABLE);
    	
    	GPIO_InitStruct.GPIO_Pin=  GPIO_Pin_0|GPIO_Pin_1;
    	GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;
    	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    	
    	
    	GPIO_Init(GPIOA, &GPIO_InitStruct);   //&x
    	
    	GPIO_InitStruct.GPIO_Pin=  GPIO_Pin_2|GPIO_Pin_3;
    	GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;
    	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;	
    	
    	GPIO_Init(GPIOB, &GPIO_InitStruct);   //&x 
    	
    	usart1_init();
    	
    	Encoder_Init();
    	
    	u16 Speed=0;
    		GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    		GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    	
    
    	while(1)
    	{
    		GPIO_SetBits(GPIOA, GPIO_Pin_0);
    		//GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    		u8 k=0;
    		
    		for(k=0;k<20;k++){
    		
    				GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    				GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    				delay(100);
    				GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    				GPIO_ResetBits(GPIOA, GPIO_Pin_1);
    				delay(100);
    				
    				GPIO_SetBits(GPIOA,GPIO_Pin_0);	
    				GPIO_SetBits(GPIOA,GPIO_Pin_0);
    				delay(100);
    				GPIO_SetBits(GPIOA,GPIO_Pin_1);		
    				GPIO_SetBits(GPIOA,GPIO_Pin_1);	
    				delay(100);
    		
    		}
    		
    		
    		Speed = Encoder_Get();								//每隔固定时间段读取一次编码器计数增量值,即为速度值
    		printf("测到的脉冲是=%d \r\n",Speed);
    	
    		
    		
    	
    	}
    }
    
    
    
    

    四、测试结果

    4.1测试方法

    将正交编码编码的信号输入STM32 PA6 PA7引脚

    因为没有编码器所以用PA0 和PA1模拟输出正交编码的PWM波形

    如果有编码器器可以直接接入 PA6 PA7

    4.2串口输出结果

    结果分析:

    这里对输入的波形滤波

    PA0 PA1 高低电平输出
    循环20次
    一次PA0循环输出1次上升沿,1次下降沿
    一次PA1循环输出1次上升沿,1次下降沿

    20*(1+1+1+1)=80
    所以计数器的次数是0

    接线


    总结

    学习使人快乐!
    音乐使人愉悦!
    日积月累使人充实和自信!

    作者:Winner1300

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32端口模拟编码器输入

    发表回复