数字罗盘采用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++;
- }
复制代码 |