Main.c #include<reg52.h> #include"1602.h" #include"pwm.h" #include"xunji.h" sbit POWER=P3^5; void main (void) { Timer0Init(); Timer1Init(); LCD_Init(); LCD_Str(5, 0, "1421h"); LCD_Str(0,0,"***smart car***"); LCD_Str(0,1,"*DANG HONG MIN*"); while(POWER) LCD_Flash(500);; DelayMs(50); LCD_Write_Command(0x01); LCD_Str(0,0,"***smart car***"); while(1) { xunji(800); } } 1602.c #include<reg52.h> #include "1602.h" #include<intrins.h> void LCD_Init() { DelayMs(15); //延迟15ms,等待LCD电源稳定,使其进入工作状态 LCD_IO = 0x00; LCD_Write_Command(LCD_DISPLAY_DOUBLE_LINE); DelayMs(5); LCD_Write_Command(LCD_DISPLAY_DOUBLE_LINE); DelayMs(5); LCD_Write_Command(LCD_DISPLAY_DOUBLE_LINE); //显示模式设置为两行显示,8位数据接口,5*8点阵 DelayMs(5); LCD_Write_Command(LCD_AC_AUTO_INCREMENT | LCD_MOVE_DISENABLE); //数据读、写操作后,AC自动增一,画面不动 DelayMs(5); LCD_Write_Command(LCD_DISPLAY_ON | LCD_CURSOR_OFF); //显示开,光标不显示 DelayMs(5); LCD_Write_Command(LCD_CLEAR_SCREEN); //清除LCD显示内容 } /************延迟函数*******************************/ void DelayUs(uchar us)//delay us { unsigned char uscnt; uscnt=us>>1; /* Crystal frequency in 12MHz*/ while(--uscnt); } void DelayMs(uchar ms)//delay Ms { while(--ms) { DelayUs(250); DelayUs(250); DelayUs(250); DelayUs(250); } } /************LCD1602写指令*******************************/ void LCD_Write_Command(uchar com) { LCD_Check_Busy(); LCD_RS = LOW; LCD_RW = LOW; _nop_(); //一个_nop_();是一个机器周期,是1us LCD_EN = HIGH; LCD_IO = com; LCD_EN = LOW; } /********************************************************/ /*****************LCD1602写数据**************************/ void LCD_Write_Data(uchar dat) { LCD_Check_Busy(); LCD_RS = HIGH; LCD_RW = LOW; _nop_(); LCD_EN=HIGH; LCD_IO=dat; LCD_EN=LOW; } /********************************************************/ /**********************显示一个字节**************************/ void LCD_Char(uchar x, uchar line, uchar dat) //从第x开始写一个字节 { unsigned char address; if (line == LINE1) // line=0,为第一行 address = LINE1_HEAD + x; else // 否则为第二行 address = LINE2_HEAD + x; LCD_Write_Command(address); LCD_Write_Data(dat); } /********************************************************/ /******************LCD1602显示字符串*********************/ void LCD_Str(uchar x,uchar line,uchar *Str) //从第line行的第x位置开始显示字符串 { uchar i = x; if (line == LINE1) { while( *Str != '\0') LCD_Char(i++, 0, *Str++); } else { while( *Str != '\0') LCD_Char(i++, 1, *Str++); } } /***************************LCD忙碌状态*******************************/ void LCD_Check_Busy(void) //检测LCD状态,看它是不是还在忙呢 { do { LCD_EN=0; LCD_RS=0; LCD_RW=1; LCD_IO=0xff; LCD_EN=1; } while (LCD_BUSY==1); LCD_EN=0; } /*****************屏幕闪烁********************/ void LCD_Flash(uchar time) { //控制停留时间 LCD_Write_Command(LCD_DISPLAY_OFF); //关闭显示 DelayMs(time); //延时 LCD_Write_Command(LCD_DISPLAY_ON); //开显示 DelayMs(time); LCD_Write_Command(LCD_DISPLAY_OFF); //关闭显示 DelayMs(time); //延时 LCD_Write_Command(LCD_DISPLAY_ON); //开显示 DelayMs(time); Pid.c #include<pid.h> #include "STC12C5A.h" #include "ioConfig.h" #include "string.h" #include "Stdio.h" #include "absacc.h" #include "intrins.h" xdata struct PID spid; // PID Control Structure unsigned int rout; // PID Response (Output) unsigned int rin; // PID Feedback (Input) unsigned int temper; unsigned int set_temper; /************************************************ PID函数 *************************************************/ void PIDInit (struct PID *pp) { memset ( pp,0,sizeof(struct PID)); } /************************************************ 增量控制PID函数体 51单片机最不擅长浮点数计算,转换成int型计算 *************************************************/ unsigned int PIDCalc( struct PID *pp, unsigned int NextPoint ) { unsigned int dError,Error,pError; //增量法计算公式: //Pdt=Kp*[E(t)-E(t-1)]+Ki*E(t)+Kd*[E(t)-2*E(t-1)+E(t-2)] Error = set_temper - NextPoint; // 偏差E(t) pError=Error-pp->LastError; //E(t)-E(t-1) dError=Error-2*pp->LastError+pp->PrevError; //E(t)-2*E(t-1)+E(t-2) pp->PrevError = pp->LastError; pp->LastError = Error; return ( pp->Proportion * pError //比例 + pp->Integral *Error //积分项 + pp->Derivative * dError // 微分项 ); } /************************************************ PID函数初始化 *************************************************/ void PIDBEGIN() { PIDInit(&spid); // Initialize Structure spid.Proportion = 10; // Set PID Coefficients spid.Integral = 5; spid.Derivative =4; } Pwm.c #include<reg52.h> #include<intrins.h> #include<pwm.h> #include<1602.h> uchar count1,high_time1,count2,high_time2; sbit Output1=P1^0; sbit Output2=P1^1; void Pwm_set1(uint zkb) { high_time1=zkb; } void Pwm_set2(uint zkb) { high_time2=zkb; } void Timer0Init(void) { // AUXR &= 0x7F; //定时器时钟12T模式 TMOD &= 0xF0; //设置定时器模式 TMOD |= 0x01; //设置定时器模式 TL0 = 0x66; //设置定时初值 TH0 = 0xFC; //设置定时初值 TF0 = 0; //清除TF0标志 TR0 = 1; //定时器0开始计时 EA=1;//开总中断 ET0=1;//开定时器0中断 } void Timer1Init(void) { // AUXR &= 0x7F; //定时器时钟12T模式 TMOD &= 0x0F; //设置定时器模式 TMOD |= 0x10; //设置定时器模式 TL1 = 0x66; //设置定时初值 TH1 = 0xFC; //设置定时初值 TF1 = 0; //清除TF0标志 TR1 = 1; //定时器0开始计时 EA=1;//开总中断 ET1=1;//开定时器1中断 } void serve_T0() interrupt 1 using 1 { TL0 = 0x66; //设置定时初值 TH0 = 0xFC; //设置定时初值 if(++count1<=(high_time1)) { Output1=1; } else if(count1<=100) { Output1=0; } else count1=0; } void serve_T1() interrupt 3 { TL1 = 0x66; //设置定时初值 TH1 = 0xFC; //设置定时初值 if(++count2<=(high_time2)) { Output2=1; } else if(count2<=100) { Output2=0; } else count2=0; } /* void pwm_init(void) { CCON=0; CL=0; CH=0; CMOD=0x02; CCAP0H=CCAP0L=0Xff; CCAPM0=0X42; CCAP1H=CCAP1L=0xff; // PCAPWM1=0X03; CCAPM1=0x42; CR=1; } */ Xunji.c #include"xunji.h" #include"1602.h" #include"pwm.h" sbit HZ = P3^6; sbit HY = P3^7; sbit Z1 = P1^2; sbit Z2 = P1^3; sbit Y1 = P1^4; sbit Y2 = P1^5; void go (uchar S) { Pwm_set1(S); Pwm_set2(S); Z1=1; Z2=0; Y1=1; Y2=0; LCD_Str(5,1,"GO ! "); } //void back(void) //{ // Pwm_set1(80); // Pwm_set2(80); // Z1=0; // Z2=1; // Y1=0; // Y2=1; // LCD_Str(5,1,"BACK !"); //} void right(void) { Pwm_set1(80); Pwm_set2(30); Z1=1; Z2=0; Y1=1; Y2=0; LCD_Str(5,1,"TURN R"); } void left(void) { Pwm_set1(30); Pwm_set2(80); Z1=1; Z2=0; Y1=1; Y2=0; LCD_Str(5,1,"TURN L"); } void stop(void) { Pwm_set1(0); Pwm_set2(0); Z1=1; Z2=1; Y1=1; Y2=1; LCD_Str(5,1,"stop "); LCD_Str(0,0,"***smart car***"); } void xunji(uchar vx) { if( (HZ==0)&&(HY==0) ) { go(vx); } else if ( (HZ==1)&&(HY==0) ) { left( ); } else if ( (HZ==0)&&(HY==1) ) { right(); } else if ( (HZ==1)&&(HY==1) ) { stop(); } }
时间: 2025-06-02 08:13:22 浏览: 39
### 51单片机智能小车代码解释与优化建议
#### 代码功能概述
该代码实现了一个基于51单片机的红外遥控小车功能。主函数通过`while(1)`循环不断调用显示函数`display()`,解析红外信号,并根据接收到的指令控制小车的运动状态[^1]。此外,还通过定时器和速度变量调整小车的速度。
#### 代码详细解释
1. **初始化部分**
在主函数中,首先调用`init()`函数完成系统的初始化工作,包括端口配置、定时器设置等。初始化完成后,设定默认速度为180。
2. **显示函数调用**
在`while(1)`循环内,每次循环都会调用`display()`函数。此函数负责刷新显示屏上的内容。然而,由于51单片机性能较低,在执行其他任务时可能导致显示间隔变长,从而产生闪烁效果。
3. **蜂鸣器控制逻辑**
如果速度超过200,则关闭蜂鸣器(`beep=0`),否则开启蜂鸣器(`beep=1`)。
4. **红外信号解析与处理**
当检测到红外信号接收成功(`isok==1`)时,调用`codeByte()`函数解析32位红外编码。如果解析成功(`Allok==1`),则根据解析结果中的特定字节值执行相应的动作:
- `timer4[2] == 0x18`:前进。
- `timer4[2] == 0x1c`:停止。
- `timer4[2] == 0x08`:左转。
- `timer4[2] == 0x5a`:右转。
- `timer4[2] == 0x52`:后退。
- `timer4[2] == 0x15`:加速。
- `timer4[2] == 0x07`:减速。
#### 优化建议
1. **减少主循环负担**
将`display()`函数从主循环中移除,改用定时器中断来驱动显示刷新。这样可以避免主循环因频繁调用`display()`而导致性能下降。例如,可以使用定时器0或定时器1中断每隔固定时间调用一次`display()`函数。
2. **提升显示刷新频率**
使用硬件定时器配合PWM(脉宽调制)技术生成稳定的显示信号,以减少屏幕闪烁现象。具体实现可以通过配置定时器模块生成精确的时间间隔。
3. **优化速度控制逻辑**
当前的速度控制逻辑较为简单,仅根据速度值开关蜂鸣器。可以进一步扩展速度控制算法,例如引入PID控制器,使小车速度变化更加平滑。
4. **代码结构改进**
将不同功能模块分离到独立的函数中,例如将红外信号解析、速度控制、方向控制等功能分别封装成独立函数,便于维护和扩展。例如:
```c
void handle_ir_command(unsigned char command) {
switch(command) {
case 0x18: move(); break;
case 0x1c: stop(); break;
case 0x08: leftmove(); break;
case 0x5a: rightmove(); break;
case 0x52: back(); break;
case 0x15: speed_up(); break;
case 0x07: speed_down(); break;
default: break;
}
}
```
5. **增加异常处理机制**
在红外信号解析过程中,增加对无效信号的处理逻辑,防止因错误信号导致小车行为异常。
#### 示例优化代码片段
以下是一个基于定时器中断的显示刷新优化示例:
```c
void timer0_ISR(void) interrupt 1 {
static unsigned char count = 0;
count++;
if (count >= 100) { // 每100次中断刷新一次显示
display();
count = 0;
}
}
void main() {
init();
speed = 180;
EA = 1; // 开启全局中断
ET0 = 1; // 开启定时器0中断
TMOD = 0x01; // 设置定时器0为模式1
TH0 = 0xFC; // 设置初值
TL0 = 0x18;
TR0 = 1; // 启动定时器0
while(1) {
if(speed > 200) beep = 0;
else beep = 1;
if(isok == 1) {
codeByte(); // 解析32位
isok = 0;
if(Allok == 1) {
handle_ir_command(timer4[2]);
}
}
}
}
```
###
阅读全文
相关推荐

















