電機驅動電路使用H橋可逆斬波電路,通過采樣電阻和旋轉編碼器測量電機轉速和電流
單片機代碼如下:
- /*
- 設計思路
- 電機驅動電路:使用H橋可逆斬波電路去驅動電機轉動,該電路可在網上查找學習相關知識。
- 電機的調速可通過改變PWM波的占空比實現,當占空比為50%時,電機不轉,
- 當占空比大于50%時電機正轉,并且越大轉速越快,但不要超過80%,超過可能會使電路發燙
- 當占空比小于50%時電機反轉,并且越小轉速越快,但不要超過20%,超過可能會使電路發燙
- 測電流是在驅動電路兩個下橋臂和電源地之間加了一個采樣電阻,通過AD轉換讀取采樣電阻電壓得到電流
- 測電機轉速是利用電機上的旋轉編碼器,編碼器為96線編碼器,所以電機轉一圈會發出96個脈沖
- 使用單片機的外部中斷,設置觸發方式為邊沿觸發,記錄脈沖數
- 使用單片機的定時器中斷,每50ms產生一次中斷,在中斷里讀取當前脈沖數,計算轉速,之后脈沖數置0
- 根據直流電機的電流與轉矩之間的關系,計算電機的轉矩
- 轉矩和扭矩是一個物理量,只是在不同的場合稱呼不同
- */
- #include "reg52.h"
- #include "iic.h"
- #include "oled.h"
- #include<stdio.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define PCF8591 0x90 //PCF8591 地址
- #define qCt 12.75
- uchar data_byte;
- u8 RH,RL,TH,TL,U8FLAG;
- sbit PWM1=P1^2;//接IN1 控制正轉
- u8 duty = 7 ; //定義占空比,H橋可逆斬波電路在50%占空比時電機不轉,大于50%正轉,小于50%反轉,
- //6表示占空比為70%,不要修改占空比,不同占空比下電機功率不同,導致扭矩計算錯誤
- u8 time;
- int pluse = 0 ; //電機編碼器的脈沖數
- float Speed = 0.0 ; //速度
- #define NOP() _nop_() /* 定義空指令 */
- #define _Nop() _nop_() /*定義空指令*/
-
- sbit m_SCL=P1^4; //I2C 時鐘
- sbit m_SDA=P1^3; //I2C 數據
- bit ack; /*應答標志位*/
-
- /*******************************************************************
- 起動總線函數
- 函數原型: void Start_I2c();
- 功能: 啟動I2C總線,即發送I2C起始條件.
- ********************************************************************/
- void Start_I2c()
- {
- m_SDA=1; /*發送起始條件的數據信號*/
- _Nop();
- m_SCL=1;
- _Nop(); /*起始條件建立時間大于4.7us,延時*/
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- m_SDA=0; /*發送起始信號*/
- _Nop(); /* 起始條件鎖定時間大于4μs*/
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- m_SCL=0; /*鉗住I2C總線,準備發送或接收數據 */
- _Nop();
- _Nop();
- }
- /*******************************************************************
- 結束總線函數
- 函數原型: void Stop_I2c();
- 功能: 結束I2C總線,即發送I2C結束條件.
- ********************************************************************/
- void Stop_I2c()
- {
- m_SDA=0; /*發送結束條件的數據信號*/
- _Nop(); /*發送結束條件的時鐘信號*/
- m_SCL=1; /*結束條件建立時間大于4μs*/
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- m_SDA=1; /*發送I2C總線結束信號*/
- _Nop();
- _Nop();
- _Nop();
- _Nop();
- }
- /*******************************************************************
- 字節數據發送函數
- 函數原型: void SendByte(UCHAR c);
- 功能: 將數據c發送出去,可以是地址,也可以是數據,發完后等待應答,并對
- 此狀態位進行操作.(不應答或非應答都使ack=0)
- 發送數據正常,ack=1; ack=0表示被控器無應答或損壞。
- ********************************************************************/
- void SendByte(unsigned char c)
- {
- unsigned char BitCnt;
-
- for(BitCnt=0;BitCnt<8;BitCnt++) /*要傳送的數據長度為8位*/
- {
- if((c<<BitCnt)&0x80)m_SDA=1; /*判斷發送位*/
- else m_SDA=0;
- _Nop();
- m_SCL=1; /*置時鐘線為高,通知被控器開始接收數據位*/
- _Nop();
- _Nop(); /*保證時鐘高電平周期大于4μs*/
- _Nop();
- _Nop();
- _Nop();
- m_SCL=0;
- }
-
- _Nop();
- _Nop();
- m_SDA=1; /*8位發送完后釋放數據線,準備接收應答位*/
- _Nop();
- _Nop();
- m_SCL=1;
- _Nop();
- _Nop();
- _Nop();
- if(m_SDA==1)ack=0;
- else ack=1; /*判斷是否接收到應答信號*/
- m_SCL=0;
- _Nop();
- _Nop();
- }
- /*******************************************************************
- 字節數據接收函數
- 函數原型: UCHAR RcvByte();
- 功能: 用來接收從器件傳來的數據,并判斷總線錯誤(不發應答信號),
- 發完后請用應答函數應答從機。
- ********************************************************************/
- unsigned char RcvByte()
- {
- unsigned char retc;
- unsigned char BitCnt;
-
- retc=0;
- m_SDA=1; /*置數據線為輸入方式*/
- for(BitCnt=0;BitCnt<8;BitCnt++)
- {
- _Nop();
- m_SCL=0; /*置時鐘線為低,準備接收數據位*/
- _Nop();
- _Nop(); /*時鐘低電平周期大于4.7μs*/
- _Nop();
- _Nop();
- _Nop();
- m_SCL=1; /*置時鐘線為高使數據線上數據有效*/
- _Nop();
- _Nop();
- retc=retc<<1;
- if(m_SDA==1)retc=retc+1; /*讀數據位,接收的數據位放入retc中 */
- _Nop();
- _Nop();
- }
- m_SCL=0;
- _Nop();
- _Nop();
- return(retc);
- }
- /********************************************************************
- 應答子函數
- 函數原型: void Ack_I2c(bit a);
- 功能: 主控器進行應答信號(可以是應答或非應答信號,由位參數a決定)
- ********************************************************************/
- void Ack_I2c(bit a)
- {
-
- if(a==0)m_SDA=0; /*在此發出應答或非應答信號 */
- else m_SDA=1;
- _Nop();
- _Nop();
- _Nop();
- m_SCL=1;
- _Nop();
- _Nop(); /*時鐘低電平周期大于4μs*/
- _Nop();
- _Nop();
- _Nop();
- m_SCL=0; /*清時鐘線,鉗住I2C總線以便繼續接收*/
- _Nop();
- _Nop();
- }
- /*******************************************************************
- DAC 變換, 轉化函數
- *******************************************************************/
- bit DACconversion(unsigned char sla,unsigned char c, unsigned char Val)
- {
- Start_I2c(); //啟動總線
- SendByte(sla); //發送器件地址
- if(ack==0)return(0);
- SendByte(c); //發送控制字節
- if(ack==0)return(0);
- SendByte(Val); //發送DAC的數值
- if(ack==0)return(0);
- Stop_I2c(); //結束總線
- return(1);
- }
- /*******************************************************************
- ADC發送字節[命令]數據函數
- *******************************************************************/
- bit ISendByte(unsigned char sla,unsigned char c)
- {
- Start_I2c(); //啟動總線
- SendByte(sla); //發送器件地址
- if(ack==0)return(0);
- SendByte(c); //發送數據
- if(ack==0)return(0);
- Stop_I2c(); //結束總線
- return(1);
- }
- unsigned char IRcvByte(unsigned char sla)
- { unsigned char c;
- Start_I2c(); //啟動總線
- SendByte(sla+1); //發送器件地址
- if(ack==0)return(0);
- c=RcvByte(); //讀取數據0
- Ack_I2c(1); //發送非就答位
- Stop_I2c(); //結束總線
- return 0;
- }
- float Get_Current(unsigned char s) //讀取電流
- {
- float t ;
- t = IRcvByte(s) ;
- if(Speed != 0 )
- {if(Speed <= 250)
- {
- t = 7.8 -0.027*Speed;
- return t ;
- }else
- {return 0.1;}
- }
- else
- {
- return 0 ;
- }
- }
- void int0() interrupt 0 using 0//外部中斷0的執行程序。
- { //interrupt 0指外部中斷0 using 0指第0組寄存器
- pluse++ ;
- }
- void timer0_init()
- {
- TMOD=0x01;//定時器0工作方式1 定時器1工作方式1
-
- TH0=0xff;
- TL0=0xa3;//定時50ms
-
- TH1=0x4b;
- TL1=0xff;//定時0.1ms
-
- IT0=1;//外部中斷0為跳變沿觸發方式
-
- EA=1;//開總中斷
- EX0=1;//打開外部中斷0
-
- ET0=1;//打開定時器0中斷開關
- TR0=1;//打開定時器0運行開關
- ET1=1;//打開定時器0中斷開關
- TR1=1;//打開定時器0運行開關
- PT1 = 0 ;
- PX0 = 1 ;
- PT0 = 1 ;
-
- }
- void tim0() interrupt 1
- {
- TR0=0; //賦初值時,關閉定時器
- TH0=0xff;
- TL0=0xa3; //定時0.1ms
- TR0=1; //打開定時器
- time++;
-
- if(time>=10) //10*0.1ms=1ms pwm波一個周期1ms,即1khz
- {
- time=0;
- }
- if(time<=duty) PWM1=1; //點空比70%
- else PWM1=0;
- }
- void tim1() interrupt 3 //定時器1的中斷服務函數
- {
- EX0 = 0 ;//關閉外部中斷,停止記錄脈沖數
- TR1=0; //賦初值時,關閉定時器
- TH1=0x4b;
- TL1=0xff; //定時50ms
- TR1=1; //打開定時器
- Speed = pluse*12.5 ; //將脈沖數轉化為轉速,編碼器為96線,轉一圈輸出96個脈沖,所以轉速=脈沖數/50ms/96*60 ,單位轉/分鐘
- pluse = 0 ;
- EX0 = 1 ;//打開外部中斷
- }
- void main() //主循環
- {
- char a[6] ;
- float Current=0.0 ;
- float T = 0.0 ;
- OLED_Init(); //初始化屏幕
- OLED_Clear();
- OLED_ShowString(0,0,"Speed:",12);//顯示字符
- OLED_ShowString(95,0,"r/m",12);
- OLED_ShowString(0,3,"I:",12);
- OLED_ShowString(95,3,"A",12);
- OLED_ShowString(0,5,"T:",12);
- OLED_ShowString(95,5,"N*m",12);
- timer0_init(); //配置定時器和外部中斷
-
- while(1)
- {
- sprintf(a,"%.1f ",Speed); //顯示速度
- OLED_ShowString(50,0,a,12);
-
-
- if(ISendByte(PCF8591,0x40))
- {
- Current= Get_Current(PCF8591);
- }
- T = Current*qCt; //電機扭矩=電流*轉矩常數*磁通量
-
- sprintf(a,"%.2f ",Current); //顯示電流
- OLED_ShowString(40,3,a,12);
-
-
- sprintf(a,"%.2f ",T); //顯示扭矩
- OLED_ShowString(40,5,a,12);
- }
-
- }
復制代碼
Keil代碼下載:
電機轉速電流.zip
(350.44 KB, 下載次數: 42)
2022-5-5 16:05 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|