編碼器是什麼玩意呢,它可是一個好玩的東西,做小車測速必不可少的玩意,下面,我將從編碼器的原理講起,一直到用stm32的編碼器接口模式,測出電機轉速與方向。
1.編碼器
圖1 編碼器示意圖
圖1為編碼器的示意圖,中間是一個帶光柵的碼盤,光通過光柵,接收管接收到高電平,沒通過,接收到低電平。電機旋轉一圈,碼盤上有多少光柵,接受管就會接收多少個高電平。371電機中的碼盤就是這樣的,他是334線碼盤,具有較高的測速精度,也就是電機轉一圈輸出334個脈衝,晶片上已集成了脈衝整形觸發電路,輸出的是矩形波,直接接單片機IO就OK。
增量式旋轉編碼器通過內部兩個光敏接受管轉化其角度碼盤的時序和相位關係,得到其角度碼盤角度位移量增加(正方向)或減少(負方向)。下圖為編碼器的原理圖:
圖2 增量式旋轉編碼器
A,B兩點對應兩個光敏接受管,A,B兩點間距為 S2 ,碼盤的光柵間距分別為S0和S1。S0+S1的距離是S2的四倍。這樣保證了A,B波形相位相差90度。旋轉的反向不同,鋸齒波A,B先到達高電平的順序就會不同,如上圖左側所示,順序的不同,就可以得到旋轉的方向。
2.stm32編碼器接口模式(寄存器)
stm32的編碼器接口模式在STM32中文參考手冊中有詳細的說明,在手冊273頁,14.3.12節。程序是完全按照 下圖方式,設置寄存器的。
圖3
從圖3中可以看出,TI1波形先於TI2波形90°時,每遇到一個邊沿變化是,計數器加1(可以通過寄存器設置加減),可以看出一個光柵,被計數了4次。TI1波形後於TI2波形90°時 ,每遇到一次邊沿變化,計數器減1。
//TIM2_Encoder_Init,Tim2_CH1(PA0);Tim2_CH2(PA1)
//arr:自動重裝值 0XFFFF
//psc:時鐘預分頻數 ,不分頻
void TIM2_Encoder_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<0; //TIM2時鐘使能
RCC->APB2ENR|=1<<2; //使能PORTA時鐘
GPIOA->CRL&=0XFFFFFF00; //PA0、PA1 清除之前設置
GPIOA->CRL|=0X00000044; //PA0、PA1 浮空輸入
TIM2->ARR=arr; //設定計數器自動重裝值
TIM2->PSC=psc; //預分頻器
TIM2->CCMR1 |= 1<<0; //輸入模式,IC1FP1映射到TI1上
TIM2->CCMR1 |= 1<<8; //輸入模式,IC2FP2映射到TI2上
TIM2->CCER |= 0<<1; //IC1不反向
TIM2->CCER |= 0<<5; //IC2不反向
TIM2->SMCR |= 3<<0; //所用輸入均在上升沿或下降沿有效
TIM2->CR1 |= 1<<0; //使能計數器
}
3 硬體
用到的模塊有STM32核心板、L298電機驅動、371帶編碼器電機(1:34)。這裡主要介紹一下電機,1:34指的是電機軸轉動34圈,電機輸出1圈。1:X,X值越小,電機的輸出轉速也就越快,扭矩也就越小;反之,X值越大,電機的輸出轉速越慢,扭矩也越大。
圖4 電機實物圖
左邊兩根黃線是電機兩極。綠線和白線是脈衝輸出線,分別接編碼器的接收管A、B,用一根可以測得速度,兩根同時用可測出電機速度與轉向。紅線和黑線是編碼器電源接線,紅正黑負,電壓3.3V-5V,不不可接反。
4 控制代碼
工作指示燈、電機方向與速度控制代碼。
//LED IO 初始化 埠PD.2 運行指示燈
void LED_Init(void)
{
RCC->APB2ENR|=1<<5; //使能PORTD時鐘
GPIOD->CRL&=0XFFFFF0FF;
GPIOD->CRL|=0X00000300; //PD.2推輓輸出
GPIOD->ODR|=1<<2; //PD.2輸出高
}
//電機旋轉方向控制信號埠初始化
//PC1~0推輓輸出,輸出高
void M_Init(void)
{
RCC->APB2ENR|=1<<4; //使能PORTC時鐘
GPIOC->CRL&=0XFFFFFF00;
GPIOC->CRL|=0X00000033; //PC1~0推輓輸出
GPIOC->ODR|=0XF<<0; //PC1~0輸出高電平
}
//定時器TIM3,PWM輸出初始化,CH1(PA6)
//arr:自動重裝值
//psc:時鐘預分頻數
//設置自動重裝值為900,那麼PWM頻率=72000/900=8Khz
////見STM32參考手冊,14.3.9PWM模式。
void TIM3_PWM_Init(u16 arr,u16 psc) //arr設定計數器自動重裝值
//psc預分頻器不分頻,psc=0
{
RCC->APB1ENR|=1<<1; //TIM3時鐘使能
GPIOA->CRL&=0XF0FFFFFF;//PA6輸出
GPIOA->CRL|=0X0B000000;//復用功能輸出
GPIOA->ODR|=1<<6;//PA6上拉
TIM3->ARR=arr;//設定計數器自動重裝值
TIM3->PSC=psc;//預分頻器不分頻
TIM3->CCMR1|=6<<4; //CH1 PWM1模式 高電平有效
TIM3->CCMR1|=1<<3; //CH1預裝載使能
TIM3->CCER|=1<<0; //OC1 輸出使能
TIM3->CR1=0x0080; //ARPE使能
TIM3->CR1|=0x01; //使能定時器3
}
//電機方向與速度控制,速度調節範圍為-100~+100
//大於0時,正轉,小於0時,反轉
// 佔空比低於0.4時電機不轉
//(佔空比是指高電平在一個周期之內所佔的時間比率)
//TIM3->CCR1的設定範圍為0~900(因為arr=900)
//見STM32參考手冊,14.3.9PWM模式。
void Motor_Speed_Control(s16 motorSpeed)
{
s16 speed = 0 ;
if(motorSpeed>100) speed = 100;
else if (motorSpeed
else speed = motorSpeed;
if(speed == 0)
{
M_1 = 0;
M_2 = 0;
}
else if(speed > 0)
{
M_1 = 0;
M_2 = 1;
TIM3->CCR1 = speed * 9;
}
else
{
M_1 = 1;
M_2 = 0;
TIM3->CCR1 = -speed * 9;
}
}
電機速度與方向檢測代碼
//TIM2_Encoder_Init,Tim2_CH1(PA0);Tim2_CH2(PA1)
//arr:自動重裝值 0XFFFF
//psc:時鐘預分頻數 ,不分頻
//見STM32中文手冊 14.3.12編碼器接口模式
void TIM2_Encoder_Init(u16 arr,u16 psc)
{
RCC->APB1ENR|=1<<0; //TIM2時鐘使能
RCC->APB2ENR|=1<<2; //使能PORTA時鐘
GPIOA->CRL&=0XFFFFFF00; //PA0、PA1 清除之前設置
GPIOA->CRL|=0X00000044; //PA0、PA1 浮空輸入
TIM2->ARR=arr; //設定計數器自動重裝值
TIM2->PSC=psc; //預分頻器
TIM2->CCMR1 |= 1<<0; //輸入模式,IC1FP1映射到TI1上
TIM2->CCMR1 |= 1<<8; //輸入模式,IC2FP2映射到TI2上
TIM2->CCER |= 0<<1; //IC1不反向
TIM2->CCER |= 0<<5; //IC2不反向
TIM2->SMCR |= 3<<0; //所用輸入均在上升沿或下降沿有效
TIM2->CR1 |= 1<<0; //使能計數器
}
//計數寄存器賦值
void TIM2_Encoder_Write(int data)
{
TIM2->CNT = data;
}
//讀計數個數
int TIM2_Encoder_Read(void)
{
TIM2_Encoder_Write(0); //計數器清0
delay_ms(10); //檢測時間,可調節
return (int)((s16)(TIM2->CNT)); //數據類型轉換
//記錄邊沿變化次數(一個柵格被記錄4次)
}
複製代碼
這裡我們只顯示邊沿變化次數,沒有具體的算出速度。
主函數
int main(void)
{
// motorSpeed的範圍為-100 ~ +100;
s16 motorSpeed = 100;
Stm32_Clock_Init(9); //系統時鐘設置
delay_init(72); //延時初始化
uart_init(72,9600); //串口1初始化
LED_Init(); //初始化與LED連接的硬體接口
M_Init(); ////初始化電機運行方向控制埠
TIM3_PWM_Init(900,0); //不分頻。PWM頻率=72000/900=8Khz
TIM2_Encoder_Init(0xffff, 0); //計數器自動重裝值為最大
while(1)
{
LED =! LED;
Motor_Speed_Control(motorSpeed);
printf("編碼器值:%d\n ",TIM2_Encoder_Read());
}
}
5 估算驗證
這裡我們只是大概的估算驗證測量值是否正確,不具有完全正確性。
我們設置motorSpeed = 100 ,得到測量值如下圖:
圖5 motorSpeed = 100
因為誤差是不可避免的,所以看到每次檢測的值都是不一樣的。我們取462,因為一個光柵被記錄了4次,所以在10ms內一共檢測到了462/4=115.5,那麼得到11.55個/ms,每ms內檢測到11.55個光柵。
通過碼錶,記錄電機輸出50圈,用時50.2s,那麼這時應該檢測到的光柵個數為50*34(電機轉34圈,輸出1圈)*334(每圈有334個光柵)=567800,除以時間,得到估算值11.31個/ms。可以看出估算值與測量值是相近的,認為測量是準確的。
設置motorSpeed = -50 ,得到測量值如下圖 :
圖6 motorSpeed=-50
可以看到測量值是負值,說明電機是反轉,與實際設置相符。
我們讀的是計數器TIM2->CNT中的值,此值為什麼會是負的,這裡為什麼這樣用? 編碼器模式中使用上下計數,假設我們初始化TIM2_Encoder_Init_1(0xff, 0);自動裝載值為0xFF,這時,計數器中的值,就會在0x00與0xFF之間循環變化,由0x01減為0x00,再減1時,計數器中的值為0xFF,我們將此數做為有符型整數處理,當然,計數的前提是每個周期的計數個數不能超過0x7F,超過,計數將不準確。
符號強制轉換,return (int)((s16)(TIM2->CNT));裡面有個類型轉換,強制轉換返回有符型數據。數值都是以補碼表示的,正整數補碼是源碼,負整數補碼是絕對值取反加1。向下計數時減1,為0時,就需要向高位借位減「1」,可以這樣理解,一個8位數00000000B-00000001B,但0不夠減1的,就向不存在的第9位借1,100000000B-00000001B=11111111B,數是以補碼形式表示的,這樣11111111B就為-1了。
在例程中,初始化自動重裝值為0xFFFF可以做個實驗,直接輸出TIM2->CNT的值看一下: printf("編碼器值1:%x \r\n",TIM2->CNT)。
推薦閱讀
基於上一次將第一章:STM32MxCube 基本使用方法,本章直接講敘述STM32配置串口2的。查看STM32F407電路圖:可得USART2接在PA2、PA3。下面新建STM32MxCube工程,開始配置。這裡我們配置IO(定義PF9、PF10引腳為LED)、RCC(使用HSE)、USART(串口)。配置USART(串口)USART的配置有好幾種,也是最常見的一種」UART異步串行通信」配置來講述。選擇USART2模式為「asynchronous」(異步通信)對應的引腳自動轉換為USART。對於系統時鐘應該都知道它的作用,就是驅動整個晶片工作的心臟,如果沒有了它,就等於人沒有了心跳。時鐘的快慢也就決定了程序的快慢。STM32
發表於 2020-05-04
完整源碼下載:https://github.com/simonliu009/STM32CubeMX-GPIO-Control軟體版本:STM32CubeMX V4.25.0 System Workbench V2.4固件庫版本:STM32Cube FW_F1 V1.6.1硬體:OneNet 麒麟座V2.3在STM32CubeMX中新建項目,選擇正確的MCU型號首先設置RCC和SYS,如下圖然後根據板子實際情況設置時鐘(麒麟座外部晶振是12M,STM32F103x的最高主頻是72M),如下圖GPIO設置 PC7, PC8, PA12和 PC10為GPIO_OUTPUT, (這是麒麟座V2.3的四個LED管腳),如下圖
發表於 2020-05-04
Cube配置USART配置在Connectivity中選中USART1MODE = AsynchronousHardware Flow Control = DisableParameter Settings中配置Baud Rate = 115200Word Length = 8bitParity = NoneStop Bits =1Data Direction = Receive and TransmitOver Sampling = 16 SamplesNVIC Setting勾選Enable,Preemption Priority =2生成代碼修改代碼生成代碼後,即可使用HAL_UART_Transmit_IT(&
發表於 2020-04-29
; PS:在明白原理的情況下建議自己手寫一次模擬UART。明白了之後,代碼重複的事就由STM32晶片的硬體功能來實現就可以了,你只需要會看邏輯分析儀或者示波器分析數據便可。 所謂硬體功能 就是你把數據填充到寄存器,然後配置好相關參數,他會自動幫你發送出去。通俗點說,自己手寫整個協議代碼實現實現就像你自己把一個快件送到到別人那裡再回來,而硬體功能則是你把快件給快遞員,快遞員幫你送過去。 明顯 後者會幫你節省大量時間和精力。它是一個硬體組成,並且你也為此付費
發表於 2020-04-29
前言: STM32串口介紹串行通信是單片機與外部設備或其他計算機交換信息的一個方式, 數據一位一位的按順序傳送, 其優點是只需要一條傳輸線, 協議簡單, 但是缺點就是傳送速度較慢。串口是單片機上非常便捷的一個工具, 當寫程序需要調試的時候, 它可以很方便的提供調試方法, 只要在一些關鍵代碼執行的地方, 通過串口給串口調試助手發送相關信息, 就可以使我們很方便的查看代碼在這個位置的執行情況。下面看一下我所使用的單片機上串口的原理圖接線外部的發送端TXD就是單片機串口的接收端USART_RX, 外部接收端RXD就是單片機串口的發送端USART_TXTXD : Transmit(TX) Data(D) Receive(RX
發表於 2020-04-29
STM32CubeMX: Version 4.26.1MDK-ARM: Version 5.24.2開發板: 中移onenet 麒麟座MINI板晶片: STM32F103CBT61.STM32CubeMX設置設置外部時鐘源設置Debug設置串口 使用USART1 PA9,PA10設置時鐘頻率設置USART1詳細參數生成MDK-ARM工程2.重定向Printf 及 Scanf主要用到兩個函數HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout
發表於 2020-04-29