#include<AT89X52.H> #include <intrins.h> //Keil外部函数库包含文件,_nop_函数在此库中 #define uint unsigned int //定义uint为无符号整型 #define uchar unsigned char //定义uchar为无符号整型 void delayXms(uint ); //声明Xms延时函数 void delay1ms(void); //声明1ms延时函数 /*********************变量定义***************************/ uint i,n,sec,min,hour; uchar sec_ge,sec_shi,min_ge,min_shi,hour_ge,hour_shi,bai,shi,ge; long int s,M; /***************小车驱动模块输入IO口*****************/ sbit IN1=P1^2; sbit IN2=P1^3; sbit IN3=P1^4; sbit IN4=P1^5; /********************液晶屏I/O口定义**********************/ sbit RS=P2^7; //寄存器选择位,将RS位定义为P2.0引脚 sbit RW=P2^6; //读写选择位,将RW位定义为P2.1引脚 sbit E =P2^5; //使能信号位,将E位定义为P2.2引脚 /********传感器接线定义********/ #define Left_led P3_7 //接循迹模块L0,左 #define Right_led P3_6 //接循迹模块R0,右 #define Left_go {P1_2=1,P1_3=0;} //左电机向前走 #define Left_back {P1_2=0,P1_3=1;} //左电机向后转 #define Left_Stop {P1_2=0,P1_3=0;} //左电机停转 #define Right_go {P1_4=1,P1_5=0;} //右电机向前走 #define Right_back {P1_4=0,P1_5=1;} //右电机向后走 #define Right_Stop {P1_4=0,P1_5=0;} //右电机停转 /*******************初使化显示数组*********************/ uchar dis1[]={"Time: h m s"}; uchar dis2[]={"Speed: mm/s"}; /************************驱动函数**************************/ //前速前进 void run(void) { Left_go ; //左电机往前走 Right_go ; //右电机往前走 } //后退函数 void backrun(void) { Left_back; //左电机往后走 Right_back; //右电机往后走 } //左转 void leftrun(void) { Right_go ; //右电机往前走 Left_back; //左电机后走 } //右转 void rightrun(void) { Left_go ; //左电机往前走 Right_back; //右电机往后走 } //停止 void stop(void) { Right_Stop ; //右电机停止 Left_Stop ; //左电机停止 } /********************X毫秒延时函数**********************/ void delayXms(uint ms) { uint k; for(k=0;k<ms;k++) {delay1ms();} } void delay1ms(void) { uint j; for(j=0;j<=120;j++) {_nop_();} } /*******************液晶显示函数*********************/ uchar lcd_busy() /*判断液晶模块的忙碌状态*/ { bit result; RS=0; RW=1; E=1; _nop_(); _nop_(); _nop_(); _nop_(); result = (bit)(P0&0x80); E=0; return result; } void lcd_wcmd(uchar cmd) /*写指令数据到LCD*/ { while(lcd_busy()); RS=0; RW=0; E=0; _nop_(); _nop_(); P0=cmd; _nop_(); _nop_(); _nop_(); _nop_(); E=1; _nop_(); _nop_(); _nop_(); _nop_(); E=0; } void lcd_pos(uchar pos) /*指定字符显示的实际地址*/ { lcd_wcmd(pos|0x80); } void lcd_wdat(uchar dat) /*将数据(字符的标准ASCII码)写入液晶模块*/ { while(lcd_busy()); RS=1; RW=0; E=0; P0=dat; _nop_(); _nop_(); _nop_(); _nop_(); E=1; _nop_(); _nop_(); _nop_(); _nop_(); E=0; } void LcdInit() /*LCD1602初始化函数*/ { delayXms(12); lcd_wcmd(0x38); delayXms(4); lcd_wcmd(0x38); delayXms(4); lcd_wcmd(0x38); delayXms(4); lcd_wcmd(0x0c); delayXms(4); lcd_wcmd(0x06); delayXms(4); lcd_wcmd(0x01); delayXms(4); } /*******************定时器1初使化函数**********************/ void T1_Init() { TMOD = 0x10; //定时器1设置为8位自动加载模式 ET1=1; //开定时器中断 EA=1; //打开总中断 IP=0x04; //设置中断优先级 TH1 = (65535-50000)/256; //初使加载50毫秒 TL1 = (65535-50000)%256; } /*******************外部中断初使化***********************/ void INT_Init() { IT0 = 1; //设置外部中断0为下降沿触发 EX0 = 1; //开外部中断0 EA = 1; //开总中断 } /********************外部中断**************************/ void my_INT0(void) interrupt 0 { M=M++; //每中断一次变量加1 } /******************定时器1中断*************************/ void timer1() interrupt 3 { TR1=0; //停止T1 TH1 = (65535-50000)/256; //求整放在高8位 TL1 = (65535-50000)%256; //求余放在低8位 n=n+1; //n++ if(n==20) //定时1秒(20个50ms为1秒) { s=M/20.00*3.14*65; //1秒钟小车左轮走s1毫米,车轮胎直径为65MM bai=(s/100)+48; //百位转换成字符 shi=(s%100/10)+48; //十位转换成字符 ge=(s%100%10)+48; //个位转换成字符 n=0; //定时器中断次数归零 sec++; //1s时间 if(sec==60) //如果秒为60,则清零,分加1 { sec=0; min++; } if(min==60) //如果分为60,则清零,时加1 { min=0; hour++; } if(hour==24) //如果时为24,则清零 { hour=0; } sec_ge=sec%10+48; //秒的个位和十位 sec_shi=sec/10+48; min_ge=min%10+48; //分的个位和十位 min_shi=min/10+48; hour_ge=hour%10+48; //时的个位和十位 hour_shi=hour/10+48; s=0; //小车左轮走的路程s1归零 M=0; //外部中断0中断次数归零 } TR1=1; //启动T1 } /************************主函数******************************/ void main() { T1_Init(); //定时器T1初使化 INT_Init(); //外部中断初使化 LcdInit(); //1602液晶显示初使化 TR1=1; //启动定时器T1 lcd_pos(0x01); i=0; while(dis1[i] != '\0') //1602液晶显示器第一行初使化显示 { lcd_wdat(dis1[i]); i++; }; i=0; lcd_pos(0x41); while(dis2[i] != '\0') //1602液晶显示器第二行初使化显示 { lcd_wdat(dis2[i]); i++; }; /******while(1)无限循环******/ while(1)
时间: 2025-06-01 14:57:45 浏览: 45
### 关于 AT89X52 单片机的小车驱动、液晶显示、定时器和中断的代码示例
#### 小车驱动
小车驱动通常涉及 PWM 调节电机速度,可以利用定时器来生成 PWM 波形。以下是基于 L298N 驱动电机的一个简单代码示例:
```c
#include <reg52.h>
sbit ENA = P2^0; // 启用端 A
sbit IN1 = P2^1; // 输入端 1
sbit IN2 = P2^2; // 输入端 2
void motor_init() {
ENA = 1; // 启用电机通道 A
}
// 设置电机方向和速度 (占空比)
void set_motor_speed(unsigned char speed, unsigned char direction) {
if(direction == 1){
IN1 = 1;
IN2 = 0;
}
else{
IN1 = 0;
IN2 = 1;
}
// 使用 PWM 来调节速度
TH0 = 256 - speed; // 计算重载值以调整占空比
}
```
此代码片段展示了如何通过改变 `TH0` 的值来控制电机的速度[^2]。
#### 液晶显示
对于 LCD 显示屏(如常见的 1602 或 16x2 字符型显示屏),可以通过并行接口连接到单片机。以下是一个简单的初始化函数和字符打印函数:
```c
#define LCD_PORT P0 // 假设 LCD 数据引脚接在 P0 口上
sbit RS = P2^3; // 寄存器选择信号
sbit RW = P2^4; // 读写信号
sbit E = P2^5; // 使能信号
void delay_ms(unsigned int ms); // 延时函数声明
void lcd_command(unsigned char cmd) {
LCD_PORT = cmd;
RS = 0; // 命令模式
RW = 0; // 写入操作
E = 1; // 打开使能
delay_ms(2);
E = 0;
}
void lcd_data(unsigned char data) {
LCD_PORT = data;
RS = 1; // 数据模式
RW = 0; // 写入操作
E = 1; // 打开使能
delay_ms(2);
E = 0;
}
void lcd_init() {
lcd_command(0x38); // 初始化为 8-bit 接口,两行显示,5x7 点阵字体
lcd_command(0x0C); // 开启显示,关闭光标
lcd_command(0x06); // 文字不动,地址自动加一
lcd_command(0x01); // 清屏命令
}
void lcd_print(char *str) {
while(*str != '\0') {
lcd_data(*str++);
}
}
```
这段代码实现了基本的 LCD 初始配置以及字符串输出功能[^1]。
#### 定时器与中断
定时器用于周期性触发事件或者生成特定频率的波形。这里提供了一个使用 Timer0 实现延时的例子:
```c
unsigned char count;
void timer0_ISR(void) interrupt 1 {
TH0 = 0xFC; // 重新加载高字节
TL0 = 0x18; // 重新加载低字节
count++;
}
void init_timer0() {
TMOD &= 0xF0; // 清除原有设置
TMOD |= 0x01; // 设定工作方式 1
TH0 = 0xFC; // 初值计算得到约 1ms 中断间隔
TL0 = 0x18;
EA = 1; // 总中断允许
ET0 = 1; // 允许定时器 0 中断
TR0 = 1; // 启动定时器
}
```
以上代码定义了每毫秒发生一次中断的服务程序,并设置了相应的计数变量以便进一步扩展逻辑[^2]。
---
###
阅读全文
相关推荐
















