數字羅盤采用IIC通信,小車電機采用定時器中斷PWM波調速,但是調速功能不能出現,小車電機一直全速轉動。
網上有人說如果使用PWM調速,因為52單片機的模擬IIC與PWM沖突(尚未解決),采取的是當需要改變小車方向時,關PWM中斷及定時器。可以在操作完了重新打開。我也加了,但效果還是這樣。
下面是代碼:
- #include "reg52.h"
- #include "intrins.h"
- #include "math.h"
- #include "stdio.h"
- typedef unsigned char u8;
- typedef unsigned int u16;
- #define Data_Port P0 //LCD1602數據端口
- #define Slave_Address 0x1a
- sbit SCL=P1^7; //IIC時鐘線
- sbit SDA=P3^2; //IIC數據線
- sbit LCD_RS=P3^5; //LCD1602命令端口
- sbit LCD_RW=P3^6; //LCD1602命令端口
- sbit LCD_EN=P3^4; //LCD1602使能端口
- sbit LED=P1^2;
- sbit zea=P2^1; //定義接口
- sbit zIN1=P2^5; //轉向輪
- sbit zIN2=P2^2; //轉向輪
- sbit zIN3=P2^4;
- sbit zIN4=P2^6;
- sbit zeb=P2^0;
- sbit yea=P1^1; //z為左邊,y為右邊
- sbit yIN1=P1^3;
- sbit yIN2=P1^4;
- sbit yIN3=P1^6; //轉向輪
- sbit yIN4=P1^5; //轉向輪
- sbit yeb=P1^2;
- u16 ynum1=0;
- u16 znum1=0;
- u8 ge=0,shi=0,bai=0,qian=0,wan=0; //顯示變量
- u8 BUF[8]=0; //數據緩沖區
- void Delay_5us()
- {
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();
- }
- void Delay_ms(u16 t)
- {
- u16 i,j;
- for(i=t;i>0;i--)
- for(j=121;j>0;j--);
- }
- /**************************************
- 起始信號
- **************************************/
- void QMC5883_Start()
- {
- SDA = 1; //拉高數據線
- SCL = 1; //拉高時鐘線
- Delay_5us(); //延時
- SDA = 0; //產生下降沿
- Delay_5us(); //延時
- SCL = 0; //拉低時鐘線
- }
- /**************************************
- 停止信號
- **************************************/
- void QMC5883_Stop()
- {
- SDA = 0; //拉低數據線
- SCL = 1; //拉高時鐘線
- Delay_5us(); //延時
- SDA = 1; //產生上升沿
- Delay_5us(); //延時
- }
- /**************************************
- 發送應答信號
- 入口參數:ack (0:ACK 1:NAK)
- **************************************/
- void QMC5883_SendACK(bit ack)
- {
- SDA = ack; //寫應答信號
- SCL = 1; //拉高時鐘線
- Delay_5us(); //延時
- SCL = 0; //拉低時鐘線
- Delay_5us(); //延時
- }
- /**************************************
- 接收應答信號
- **************************************/
- bit QMC5883_RecvACK()
- {
- SCL = 1; //拉高時鐘線
- Delay_5us(); //延時
- CY = SDA; //進位標志 讀應答信號
- SCL = 0; //拉低時鐘線
- Delay_5us(); //延時
- return CY;
- }
- /**************************************
- 向IIC總線發送一個字節數據
- **************************************/
- void QMC5883_SendByte(u8 dat)
- {
- u8 i;
- for (i=0; i<8; i++) //8位計數器
- {
- dat <<= 1; //移出數據的最高位
- SDA = CY; //送數據口
- SCL = 1; //拉高時鐘線
- Delay_5us(); //延時
- SCL = 0; //拉低時鐘線
- Delay_5us(); //延時
- }
- QMC5883_RecvACK();
- }
- /**************************************
- 從IIC總線接收一個字節數據
- **************************************/
- u8 QMC5883_RecvByte()
- {
- u8 i;
- u8 dat = 0;
- SDA = 1; //使能內部上拉,準備讀取數據,
- for (i=0; i<8; i++) //8位計數器
- {
- dat <<= 1;
- SCL = 1; //拉高時鐘線
- Delay_5us(); //延時
- dat |= SDA; //讀數據
- SCL = 0; //拉低時鐘線
- Delay_5us(); //延時
- }
- return dat;
- }
- //************************寫入單字節數據***************************
- void Single_Write_QMC5883(u8 REG_Address,u8 REG_data)
- {
- QMC5883_Start(); //起始信號
- QMC5883_SendByte(Slave_Address); //發送設備地址+寫信號
- QMC5883_SendByte(REG_Address); //內部寄存器地址,請參考中文pdf
- QMC5883_SendByte(REG_data); //內部寄存器數據,請參考中文pdf
- QMC5883_Stop(); //發送停止信號
- }
- //************************讀取單字節數據*************************
- //u8 Single_Read_QMC5883(u8 REG_Address)
- //{
- // u8 REG_data;
- // QMC5883_Start(); //起始信號
- // QMC5883_SendByte(Slave_Address); //發送設備地址+寫信號
- // QMC5883_SendByte(REG_Address); //發送存儲單元地址,從0開始
- // QMC5883_Start(); //起始信號
- // QMC5883_SendByte(Slave_Address+1); //發送設備地址+讀信號
- // REG_data=QMC5883_RecvByte(); //讀出寄存器數據
- // QMC5883_SendACK(1);
- // QMC5883_Stop(); //停止信號
- // return REG_data;
- //}
- //******************************************************
- //連續讀出QMC5883內部角度數據,地址范圍0x00~0x05
- //******************************************************
- void Multiple_Read_QMC5883(void)
- {
- u8 i;
- QMC5883_Start(); //起始信號
- QMC5883_SendByte(Slave_Address); //發送設備地址+寫信號
- QMC5883_SendByte(0x00); //發送存儲單元地址,從0x00開始
- QMC5883_Start(); //起始信號
- QMC5883_SendByte(Slave_Address+1); //發送設備地址+讀信號
- for (i=0; i<6; i++) //連續讀取6個地址數據,存儲中BUF
- {
- BUF[i] = QMC5883_RecvByte(); //BUF[0]存儲數據
- if (i == 5)
- {
- QMC5883_SendACK(1); //最后一個數據需要回非應答NOACK
- }
- else
- {
- QMC5883_SendACK(0); //應答ACK
- }
- }
- QMC5883_Stop(); //停止信號
- Delay_ms(5);
- }
- //初始化QMC5883,根據需要請參考pdf進行修改****
- void Init_QMC5883()
- {
- Single_Write_QMC5883(0x09,0x0d); //控制寄存器配置
- Single_Write_QMC5883(0x0b,0x01); //設置清除時間寄存器
- Single_Write_QMC5883(0x20,0x40); //
- Single_Write_QMC5883(0x21,0x01); //
- }
- /***************等待LCD使能****************/
- void Wait_For_Enable(void)
- {
- Data_Port=0xff;
- LCD_RS=0;
- LCD_RW=1;
- _nop_();
- LCD_EN=1;
- _nop_();
- _nop_();
- while(Data_Port&0x80);
- LCD_EN=0;
- }
- /**************寫LCD命令函數*****************/
- void Write_Command_LCD(u8 CMD,u8 Attribc)
- {
- if(Attribc)Wait_For_Enable();
- LCD_RS=0;
- LCD_RW=0;
- _nop_();
- Data_Port=CMD;
- _nop_();
- LCD_EN=1;
- _nop_();
- _nop_();
- LCD_EN=0;
- }
- /**************寫LCD數據寄存器*****************/
- void Write_Data_LCD(u8 dataW)
- {
- Wait_For_Enable();
- LCD_RS=1;
- LCD_RW=0;
- _nop_();
- Data_Port=dataW;
- _nop_();
- LCD_EN=1;
- _nop_();
- _nop_();
- LCD_EN=0;
- }
- /****************初始化LCD*******************/
- void Init_Lcd()
- {
- Write_Command_LCD(0x38,1);
- Write_Command_LCD(0x08,1);
- Write_Command_LCD(0x01,1);
- Write_Command_LCD(0x06,1);
- Write_Command_LCD(0x0c,1);
- }
- /****************顯示一個字符*******************/
- void Display_One_Char(u8 X,u8 Y,u8 DData)
- {
- Y&=1;
- X&=15;
- if(Y)X|=0x40;
- X|=0x80;
- Write_Command_LCD(X,0);
- Write_Data_LCD(DData);
- }
- //******************************顯示在LCD的數據取位********************************//
- void Conversion(u16 temp_data)
- {
- wan=temp_data/10000+0x30 ;
- temp_data=temp_data%10000; //取余運算
- qian=temp_data/1000+0x30 ;
- temp_data=temp_data%1000; //取余運算
- bai=temp_data/100+0x30 ;
- temp_data=temp_data%100; //取余運算
- shi=temp_data/10+0x30 ;
- temp_data=temp_data%10; //取余運算
- ge=temp_data+0x30;
- }
- void fanwei()
- {
- // u16 i;
- int x=0,y=0,z=0;
- double angle=0;
- Delay_ms(200);
- Init_Lcd();
- Init_QMC5883();
- Delay_ms(300);
- Multiple_Read_QMC5883(); //連續讀取三軸角度數據,存儲在BUF中
- //---------顯示XY軸
- x=BUF[1] << 8 | BUF[0]; //Combine MSB and LSB of X Data output register 最高有效位
- y=BUF[3] << 8 | BUF[2]; //Combine MSB and LSB of Y Data output register
- z=BUF[5] << 8 | BUF[4]; //Combine MSB and LSB of Z Data output register
- angle= atan2((double)y,(double)x) * (180 / 3.14159265) + 180; //計算角度
- angle*=10;
- Conversion(angle); //計算角度數據和顯示
- Display_One_Char(2,0,'A');
- Display_One_Char(3,0,':');
- Display_One_Char(4,0,qian);
- Display_One_Char(5,0,bai);
- Display_One_Char(6,0,shi);
- Display_One_Char(7,0,'.');
- Display_One_Char(8,0,ge);
- Delay_ms(100); //延時
- }
- void time0_init() //定時器初始化
- {
- TMOD=0x01; //T0工作方式1
- EA=1;
- ET0=1;
- TR0=1;
- TH0=(65536-917)/256; //1ms 進入一次中斷
- TL0=(65536-917)%256;
- }
- void time0_stop() //關閉中斷
- {
- EA=0;
- ET0=0;
- TR0=0;
-
- }
- void chang_pwm1(u16 znum3,u16 ynum3) //zum3,yum3為車速
- {
- if(znum1>znum3)
- {
- zea=0;
- zeb=0;
- }
- else
- {
- zea=1;
- zeb=1;
- }
- if(ynum1>ynum3)
- {
- yea=0;
- yeb=0;
- }
- else
- {
- yea=1;
- yeb=1;
- }
- if(znum1>50)
- {
- znum1=0;
- }
- if(ynum1>50)
- {
- ynum1=0;
- }
- }
- void turn_right()
- {
- chang_pwm1(20,10); //右拐
- }
- void turn_wei() //變向
- {
- zIN1=0;
- zIN2=1;
- yIN3=1;
- yIN4=0;
- zIN3=0;
- zIN4=0;
- yIN1=0;
- yIN2=0;
- chang_pwm1(10,10);
- }
- void go_straight()
- {
- chang_pwm1(10,10); //直行
- }
- void init() //初始化
- {
- yea=1;
- yIN1=1;
- yIN2=0;
- yIN3=1;
- yIN4=0;
- yeb=1;
- zea=1;
- zIN1=1;
- zIN2=0;
- zIN3=1;
- zIN4=0;
- zeb=1;
- }
- void main()
- {
- while(1)
- {
- fanwei();
- if((qian!='2')||((bai!='4')&&(bai!='5')))
- {
- init();
- time0_init();
- turn_wei();
- }
- else
- {
- init();
- time0_init();
- go_straight();
- }
- time0_stop();
- }
- }
- void T0_time()interrupt 1 //中斷程序1
- {
- TH0=(65536-917)/256; //1ms 進入一次中斷
- TL0=(65536-917)%256;
- znum1++;
- ynum1++;
- }
復制代碼 |