標(biāo)題:
才入門的單片機(jī)新手請教大家關(guān)于直流電機(jī)調(diào)速的問題
[打印本頁]
作者:
256202
時(shí)間:
2019-12-31 19:32
標(biāo)題:
才入門的單片機(jī)新手請教大家關(guān)于直流電機(jī)調(diào)速的問題
不是一般的pwm控制,就是幾個(gè)AD/DA的轉(zhuǎn)換,用三極管放大控制電樞電流..........第一次寫這種幾百行的大程序感覺好難啊
問題是在proteus上調(diào)試發(fā)現(xiàn)速度只能加,設(shè)置速度比實(shí)際速度小的時(shí)候就不能降速了,代碼也不能發(fā)現(xiàn)問題,來求助大家
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
調(diào)速.png
(278.03 KB, 下載次數(shù): 37)
下載附件
2019-12-31 19:32 上傳
以下是單片機(jī)代碼
#include <reg52.h>
#define digital P0 //DAC0832 數(shù)據(jù)管腳
#define leddat P1 //數(shù)碼管數(shù)據(jù)管腳
#define en 1 //電機(jī)一圈的脈沖數(shù) 根據(jù)電機(jī)實(shí)際參數(shù)設(shè)定
#define uint unsigned int
#define uchar unsigned char
#define ufloat unsigned float
sbit scl=P3^5;
sbit sda=P3^7;
sbit Y3 = P3^0; //數(shù)碼管段選腳定義
sbit Y2 = P3^1;
sbit Y1 = P3^2;
sbit Y0 = P3^3;
sbit Y7 = P2^0; //數(shù)碼管段選腳定義
sbit Y6 = P2^1;
sbit Y5 = P2^2;
sbit Y4 = P2^3;
sbit LSA = P2^4; //138譯碼器管腳定義
sbit LSB = P2^5;
sbit LSC = P2^6;
sbit LSG1 = P2^7;
char code Led_dat[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //共陰數(shù)碼管段碼 0123456789
long double speed=0;
long int count=0; //記錄脈沖數(shù)量
void Delay10us()
{
unsigned char a,b;
for(b=1;b>0;b--)
for(a=2;a>0;a--);
}
void delay() //延時(shí)幾微秒。延時(shí)函數(shù)在很多函數(shù)里都要用它。至少要大于4.7us
{;;} //當(dāng)你把這個(gè)函數(shù)寫在用它這個(gè)函數(shù)的前面就不用聲明了
void init() //初始化總線。將總線都拉高以釋放
{
scl=1;
delay(); //I2C總線使用時(shí)一般都要延時(shí)5us左右
sda=1;
delay();
}
void start() //啟始信號。 時(shí)鐘信號為高電平期間,數(shù)據(jù)總線產(chǎn)生下降沿。
{ //為什么要下降沿,且sda先要為1。因?yàn)橄纫WC數(shù)據(jù)線為空才能工作
sda=1; //先釋放數(shù)據(jù)總線。高電平釋放
delay();
scl=1;
delay();
sda=0;
delay();
}
void stop()
{
sda=0; //先要有工作狀態(tài)才能釋放,sda=0時(shí)在工作狀態(tài)
delay();
scl=1;
delay();
sda=1; //釋放數(shù)據(jù)總線
delay();
}
void respons() //應(yīng)答函數(shù)
{
uchar i=0;
scl=1; //每個(gè)字節(jié)發(fā)送完后的第九個(gè)時(shí)鐘信號的開始
delay();
while((sda==1)&&(i<255)) //此處i的定義使用了uchar.只要填一個(gè)小于255的就行
i++; //此處的sda是從機(jī)的
scl=0; //表示主器件默認(rèn)從器件已經(jīng)收到而不再等待。不再等待之后,時(shí)鐘的高電平過了就是低電平,所以scl=0
//此時(shí)第酒個(gè)時(shí)鐘信號結(jié)束
}
void writebyte(uchar d) //寫一字節(jié),每次左移一位
{
uchar i,temp;
temp=d;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0; //數(shù)據(jù)傳輸期間要想sda可變,先把時(shí)鐘拉低。此處要給sda賦值
delay();
sda=CY; //CY為左移移入PSW寄存器中的的CY位。
delay();
scl=1; //sda有數(shù)據(jù)了。保持?jǐn)?shù)據(jù)穩(wěn)定
delay();
}
scl=0; //此處是寫數(shù)據(jù),是屬于數(shù)據(jù)傳輸過程中。只有在時(shí)鐘信號為低電平期間
delay(); //數(shù)據(jù)總線才可以變化。
sda=1; //所以要想釋放數(shù)據(jù)總線,就必須先把時(shí)鐘拉低
delay();
/*此處釋放總線寫在末尾是因?yàn)檎{(diào)用它時(shí),前面有起始函數(shù)釋放了總線*/
}
uchar readbyte()
{
uchar i,k;
scl=0;
delay();
sda=1;
delay();
/*此處釋放總線放在前面是因?yàn)橐话愣际窍葘懞笞x,保險(xiǎn)起見,釋放一下總線*/
for(i=0;i<8;i++)
{
scl=1; //一個(gè)時(shí)鐘信號的開始
delay();
k=(k<<1)|sda; //實(shí)質(zhì)是把sda的數(shù)據(jù),最先傳來的放在最高位,依次往下排
scl=0; //一個(gè)時(shí)鐘信號結(jié)束
delay();
}
return k;
}
void write(uchar addr,uchar dat)
{
start(); //初始化
writebyte(0x90); //調(diào)用寫一字節(jié)函數(shù).PCF8591為1001。此處是給從機(jī)發(fā)送寫信號(最低位是0)
respons(); //調(diào)用應(yīng)答函數(shù)讓從機(jī)應(yīng)答
writebyte(addr); //寫入地址
respons(); //每寫一字節(jié)都要應(yīng)答
writebyte(dat);
respons();
stop();
}
uchar read(uchar addr)
{
uchar dat;
start();
writebyte(0x90); //從此處的發(fā)送地址和方向位0到從機(jī)
respons(); //此處的從機(jī)產(chǎn)生應(yīng)答。屬于“偽寫”。用于確定和哪臺機(jī)子通信
writebyte(addr);
respons();
start();
writebyte(0x91); //從此處開始,從機(jī)向主機(jī)寫數(shù)據(jù)。讀的方向位為1
respons();
dat=readbyte();
stop();
return dat; //讀得的數(shù)據(jù)要返回
}
void delay1(int i) //延時(shí)函數(shù)
{
while(i--);
}
void display(int x,int y) //數(shù)碼管操作函數(shù)
{
delay1(100);
leddat = ~0x00; //清屏消隱
Y0=0;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1; //段選1
leddat = ~Led_dat[x%10]; //取余數(shù) 取出個(gè)位數(shù)
delay1(100);
leddat = ~0x00;
Y0=1;Y1=0;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1; //段選2
leddat = ~Led_dat[x/10%10]; //取出十位數(shù)
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=0;Y3=1;Y4=1;Y5=1;Y6=1;Y7=1; //段選3
leddat = ~Led_dat[x/100%10]; //取出百位數(shù)
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=1;Y3=0;Y4=1;Y5=1;Y6=1;Y7=1; //段選4
leddat = ~Led_dat[x/1000]; //取出千位數(shù)
delay1(100);
leddat = ~0x00; //清屏消隱
Y0=1;Y1=1;Y2=1;Y3=1;Y4=0;Y5=1;Y6=1;Y7=1; //段選5
leddat = ~Led_dat[y%10]; //取余數(shù) 取出個(gè)位數(shù)
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=0;Y6=1;Y7=1; //段選6
leddat = ~Led_dat[y/10%10]; //取出十位數(shù)
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=0;Y7=1; //段選7
leddat = ~Led_dat[y/100%10]; //取出百位數(shù)
delay1(100);
leddat = ~0x00;
Y0=1;Y1=1;Y2=1;Y3=1;Y4=1;Y5=1;Y6=1;Y7=0; //段選8
leddat = ~Led_dat[y/1000]; //取出千位數(shù)
}
void timerInit()
{
TMOD=0x15; //模式設(shè)置,00000001
TR0=1; //打開計(jì)數(shù)器
ET0=1; //開計(jì)數(shù)器0中斷
TR1=1; //打開計(jì)數(shù)器
ET1=1; //開計(jì)數(shù)器0中斷
TH1=(65536-45872)/256; //50ms
TL1=(65536-45872)%256;
TH0=0;
TL0=0;
EA=1; //開總中斷
}
uint T0_read()
{
uchar tl,th1,th2;
uint val;
while(1)
{
th1=TH0;
tl=TL0;
th2=TH0;
if(th1==th2)
break;
}
val=th1*256+tl;
return val;
}
void main()
{
double dat = 0;
int dig=0;
int i;
int x_speed=150; //速度增量
LSA = 0; //138譯碼器 YC2輸出低
LSB = 1;
LSC = 0;
LSG1 = 1;
WR = 0; //打開dac0830轉(zhuǎn)換 WR輸出低
timerInit();
while(1)
{
dat=read(0x00);
dat = (dat*67)/255 + 17; //設(shè)定的每秒轉(zhuǎn)速 17~84r/s 對應(yīng) 1020~5040r/min
speed = count/en; //當(dāng)前速度
if(speed < dat) x_speed+=1; //如果實(shí)際速度小于設(shè)定速度 速度增量加
else x_speed-=1; //反之則減
if(x_speed > 255)x_speed = 255; //速度增量最大255 最小0
if(x_speed < 0) x_speed = 0;
digital =x_speed; //電機(jī)輸出速度為 設(shè)定速度加上速度增量
i=10;
while(i--)
{
i--;
display(speed*60,dat*60); //顯示當(dāng)前速度 每分鐘轉(zhuǎn)速
}
}
}
void timer_T1() interrupt 3 //定時(shí)器中斷
{
static int i = 0;
TH1=(65536-45872)/256; //50ms
TL1=(65536-45872)%256;
i++;
if(i>=20) //20*50=1000ms 定時(shí)1s
{
TR0=0; //關(guān)閉計(jì)數(shù)器 記錄脈沖數(shù)量
count=T0_read();
TH0=0;
TL0=0;
i=0; //脈沖清零 重新開始計(jì)數(shù)
TR0=1;
}
}
復(fù)制代碼
全部資料51hei下載地址:
調(diào)速.zip
(115.21 KB, 下載次數(shù): 14)
2019-12-31 19:24 上傳
點(diǎn)擊文件名下載附件
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1