不是一般的pwm控制,就是幾個AD/DA的轉換,用三極管放大控制電樞電流..........第一次寫這種幾百行的大程序感覺好難啊
問題是在proteus上調試發現速度只能加,設置速度比實際速度小的時候就不能降速了,代碼也不能發現問題,來求助大家
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
調速.png (278.03 KB, 下載次數: 37)
下載附件
2019-12-31 19:32 上傳
以下是單片機代碼
- #include <reg52.h>
- #define digital P0 //DAC0832 數據管腳
- #define leddat P1 //數碼管數據管腳
- #define en 1 //電機一圈的脈沖數 根據電機實際參數設定
- #define uint unsigned int
- #define uchar unsigned char
- #define ufloat unsigned float
- sbit scl=P3^5;
- sbit sda=P3^7;
- sbit Y3 = P3^0; //數碼管段選腳定義
- sbit Y2 = P3^1;
- sbit Y1 = P3^2;
- sbit Y0 = P3^3;
- sbit Y7 = P2^0; //數碼管段選腳定義
- 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}; //共陰數碼管段碼 0123456789
- long double speed=0;
- long int count=0; //記錄脈沖數量
- void Delay10us()
- {
- unsigned char a,b;
- for(b=1;b>0;b--)
- for(a=2;a>0;a--);
- }
- void delay() //延時幾微秒。延時函數在很多函數里都要用它。至少要大于4.7us
- {;;} //當你把這個函數寫在用它這個函數的前面就不用聲明了
- void init() //初始化總線。將總線都拉高以釋放
- {
- scl=1;
- delay(); //I2C總線使用時一般都要延時5us左右
- sda=1;
- delay();
- }
- void start() //啟始信號。 時鐘信號為高電平期間,數據總線產生下降沿。
- { //為什么要下降沿,且sda先要為1。因為先要保證數據線為空才能工作
- sda=1; //先釋放數據總線。高電平釋放
- delay();
- scl=1;
- delay();
- sda=0;
- delay();
- }
- void stop()
- {
- sda=0; //先要有工作狀態才能釋放,sda=0時在工作狀態
- delay();
- scl=1;
- delay();
- sda=1; //釋放數據總線
- delay();
- }
- void respons() //應答函數
- {
- uchar i=0;
- scl=1; //每個字節發送完后的第九個時鐘信號的開始
- delay();
- while((sda==1)&&(i<255)) //此處i的定義使用了uchar.只要填一個小于255的就行
- i++; //此處的sda是從機的
- scl=0; //表示主器件默認從器件已經收到而不再等待。不再等待之后,時鐘的高電平過了就是低電平,所以scl=0
- //此時第酒個時鐘信號結束
- }
- void writebyte(uchar d) //寫一字節,每次左移一位
- {
- uchar i,temp;
- temp=d;
- for(i=0;i<8;i++)
- {
- temp=temp<<1;
- scl=0; //數據傳輸期間要想sda可變,先把時鐘拉低。此處要給sda賦值
- delay();
- sda=CY; //CY為左移移入PSW寄存器中的的CY位。
- delay();
- scl=1; //sda有數據了。保持數據穩定
- delay();
- }
- scl=0; //此處是寫數據,是屬于數據傳輸過程中。只有在時鐘信號為低電平期間
- delay(); //數據總線才可以變化。
- sda=1; //所以要想釋放數據總線,就必須先把時鐘拉低
- delay();
- /*此處釋放總線寫在末尾是因為調用它時,前面有起始函數釋放了總線*/
- }
- uchar readbyte()
- {
- uchar i,k;
- scl=0;
- delay();
- sda=1;
- delay();
- /*此處釋放總線放在前面是因為一般都是先寫后讀,保險起見,釋放一下總線*/
- for(i=0;i<8;i++)
- {
- scl=1; //一個時鐘信號的開始
- delay();
- k=(k<<1)|sda; //實質是把sda的數據,最先傳來的放在最高位,依次往下排
- scl=0; //一個時鐘信號結束
- delay();
- }
- return k;
- }
- void write(uchar addr,uchar dat)
- {
- start(); //初始化
- writebyte(0x90); //調用寫一字節函數.PCF8591為1001。此處是給從機發送寫信號(最低位是0)
- respons(); //調用應答函數讓從機應答
- writebyte(addr); //寫入地址
- respons(); //每寫一字節都要應答
- writebyte(dat);
- respons();
- stop();
- }
- uchar read(uchar addr)
- {
- uchar dat;
- start();
- writebyte(0x90); //從此處的發送地址和方向位0到從機
- respons(); //此處的從機產生應答。屬于“偽寫”。用于確定和哪臺機子通信
- writebyte(addr);
- respons();
- start();
- writebyte(0x91); //從此處開始,從機向主機寫數據。讀的方向位為1
- respons();
- dat=readbyte();
- stop();
- return dat; //讀得的數據要返回
- }
- void delay1(int i) //延時函數
- {
- while(i--);
- }
- void display(int x,int y) //數碼管操作函數
- {
- 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]; //取余數 取出個位數
-
- 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]; //取出十位數
-
- 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]; //取出百位數
-
- 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]; //取出千位數
-
- 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]; //取余數 取出個位數
-
- 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]; //取出十位數
-
- 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]; //取出百位數
-
- 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]; //取出千位數
- }
- void timerInit()
- {
- TMOD=0x15; //模式設置,00000001
- TR0=1; //打開計數器
- ET0=1; //開計數器0中斷
-
- TR1=1; //打開計數器
- ET1=1; //開計數器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轉換 WR輸出低
- timerInit();
- while(1)
- {
- dat=read(0x00);
- dat = (dat*67)/255 + 17; //設定的每秒轉速 17~84r/s 對應 1020~5040r/min
-
- speed = count/en; //當前速度
-
- if(speed < dat) x_speed+=1; //如果實際速度小于設定速度 速度增量加
- else x_speed-=1; //反之則減
- if(x_speed > 255)x_speed = 255; //速度增量最大255 最小0
- if(x_speed < 0) x_speed = 0;
- digital =x_speed; //電機輸出速度為 設定速度加上速度增量
-
- i=10;
- while(i--)
- {
- i--;
- display(speed*60,dat*60); //顯示當前速度 每分鐘轉速
- }
-
- }
- }
- void timer_T1() interrupt 3 //定時器中斷
- {
- static int i = 0;
- TH1=(65536-45872)/256; //50ms
- TL1=(65536-45872)%256;
- i++;
- if(i>=20) //20*50=1000ms 定時1s
- {
- TR0=0; //關閉計數器 記錄脈沖數量
- count=T0_read();
- TH0=0;
- TL0=0;
- i=0; //脈沖清零 重新開始計數
- TR0=1;
- }
- }
復制代碼 全部資料51hei下載地址:
調速.zip
(115.21 KB, 下載次數: 14)
2019-12-31 19:24 上傳
點擊文件名下載附件
|