標題:
51單片機電機驅動及電機速度電流測量程序
[打印本頁]
作者:
ascsca
時間:
2022-5-5 16:05
標題:
51單片機電機驅動及電機速度電流測量程序
電機驅動電路使用H橋可逆斬波電路,通過采樣電阻和旋轉編碼器測量電機轉速和電流
單片機代碼如下:
/*
設計思路
電機驅動電路:使用H橋可逆斬波電路去驅動電機轉動,該電路可在網上查找學習相關知識。
電機的調速可通過改變PWM波的占空比實現,當占空比為50%時,電機不轉,
當占空比大于50%時電機正轉,并且越大轉速越快,但不要超過80%,超過可能會使電路發(fā)燙
當占空比小于50%時電機反轉,并且越小轉速越快,但不要超過20%,超過可能會使電路發(fā)燙
測電流是在驅動電路兩個下橋臂和電源地之間加了一個采樣電阻,通過AD轉換讀取采樣電阻電壓得到電流
測電機轉速是利用電機上的旋轉編碼器,編碼器為96線編碼器,所以電機轉一圈會發(fā)出96個脈沖
使用單片機的外部中斷,設置觸發(fā)方式為邊沿觸發(fā),記錄脈沖數
使用單片機的定時器中斷,每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總線,即發(fā)送I2C起始條件.
********************************************************************/
void Start_I2c()
{
m_SDA=1; /*發(fā)送起始條件的數據信號*/
_Nop();
m_SCL=1;
_Nop(); /*起始條件建立時間大于4.7us,延時*/
_Nop();
_Nop();
_Nop();
_Nop();
m_SDA=0; /*發(fā)送起始信號*/
_Nop(); /* 起始條件鎖定時間大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
m_SCL=0; /*鉗住I2C總線,準備發(fā)送或接收數據 */
_Nop();
_Nop();
}
/*******************************************************************
結束總線函數
函數原型: void Stop_I2c();
功能: 結束I2C總線,即發(fā)送I2C結束條件.
********************************************************************/
void Stop_I2c()
{
m_SDA=0; /*發(fā)送結束條件的數據信號*/
_Nop(); /*發(fā)送結束條件的時鐘信號*/
m_SCL=1; /*結束條件建立時間大于4μs*/
_Nop();
_Nop();
_Nop();
_Nop();
_Nop();
m_SDA=1; /*發(fā)送I2C總線結束信號*/
_Nop();
_Nop();
_Nop();
_Nop();
}
/*******************************************************************
字節(jié)數據發(fā)送函數
函數原型: void SendByte(UCHAR c);
功能: 將數據c發(fā)送出去,可以是地址,也可以是數據,發(fā)完后等待應答,并對
此狀態(tài)位進行操作.(不應答或非應答都使ack=0)
發(fā)送數據正常,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; /*判斷發(fā)送位*/
else m_SDA=0;
_Nop();
m_SCL=1; /*置時鐘線為高,通知被控器開始接收數據位*/
_Nop();
_Nop(); /*保證時鐘高電平周期大于4μs*/
_Nop();
_Nop();
_Nop();
m_SCL=0;
}
_Nop();
_Nop();
m_SDA=1; /*8位發(fā)送完后釋放數據線,準備接收應答位*/
_Nop();
_Nop();
m_SCL=1;
_Nop();
_Nop();
_Nop();
if(m_SDA==1)ack=0;
else ack=1; /*判斷是否接收到應答信號*/
m_SCL=0;
_Nop();
_Nop();
}
/*******************************************************************
字節(jié)數據接收函數
函數原型: UCHAR RcvByte();
功能: 用來接收從器件傳來的數據,并判斷總線錯誤(不發(fā)應答信號),
發(fā)完后請用應答函數應答從機。
********************************************************************/
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; /*在此發(fā)出應答或非應答信號 */
else m_SDA=1;
_Nop();
_Nop();
_Nop();
m_SCL=1;
_Nop();
_Nop(); /*時鐘低電平周期大于4μs*/
_Nop();
_Nop();
_Nop();
m_SCL=0; /*清時鐘線,鉗住I2C總線以便繼續(xù)接收*/
_Nop();
_Nop();
}
/*******************************************************************
DAC 變換, 轉化函數
*******************************************************************/
bit DACconversion(unsigned char sla,unsigned char c, unsigned char Val)
{
Start_I2c(); //啟動總線
SendByte(sla); //發(fā)送器件地址
if(ack==0)return(0);
SendByte(c); //發(fā)送控制字節(jié)
if(ack==0)return(0);
SendByte(Val); //發(fā)送DAC的數值
if(ack==0)return(0);
Stop_I2c(); //結束總線
return(1);
}
/*******************************************************************
ADC發(fā)送字節(jié)[命令]數據函數
*******************************************************************/
bit ISendByte(unsigned char sla,unsigned char c)
{
Start_I2c(); //啟動總線
SendByte(sla); //發(fā)送器件地址
if(ack==0)return(0);
SendByte(c); //發(fā)送數據
if(ack==0)return(0);
Stop_I2c(); //結束總線
return(1);
}
unsigned char IRcvByte(unsigned char sla)
{ unsigned char c;
Start_I2c(); //啟動總線
SendByte(sla+1); //發(fā)送器件地址
if(ack==0)return(0);
c=RcvByte(); //讀取數據0
Ack_I2c(1); //發(fā)送非就答位
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的執(zhí)行程序。
{ //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為跳變沿觸發(fā)方式
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() //主循環(huán)
{
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
作者:
heicad
時間:
2022-5-5 20:39
樓主你好 能分享一下原理圖嗎?這個是怎么測電流的?用的什么芯片?
作者:
ascsca
時間:
2022-5-5 23:00
heicad 發(fā)表于 2022-5-5 20:39
樓主你好 能分享一下原理圖嗎?這個是怎么測電流的?用的什么芯片?
用的采樣電阻,在GND和下橋臂之間接一個0.05的采樣電阻,把采樣電阻上的壓降放大20倍,ADC采樣之后的電壓就是電流
作者:
m182892
時間:
2022-5-6 08:37
電機扭矩=電流*轉矩常數*磁通量,這個公式中轉矩常數是馬達規(guī)格書上有注明嗎,還有磁通量怎么測試的
作者:
lipen2008
時間:
2022-5-6 12:36
能分享一下原理圖嗎?
作者:
愿世間且清塵
時間:
2022-12-17 17:33
heicad 發(fā)表于 2022-5-5 20:39
樓主你好 能分享一下原理圖嗎?這個是怎么測電流的?用的什么芯片?
應該是L298或者L297
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1