文章目录
一、利用中断发出1Khz的方波信号,驱动蜂鸣器鸣叫
电路图:
代码:
#include <reg51.h> // 包含头文件
sbit sound = P1^7; // 将 sound 位定义为 P1.7 脚
#define f1(a) (65536-a)/256 // 定义装入定时器高8位时间常数
#define f2(a) (65536-a)%256 // 定义装入定时器低8位时间常数
unsigned int i = 500;
unsigned int j = 0;
void main(void) {
EA = 1; // 开总中断.
ET1 = 1; // 允许定时器 T1 中断.
TMOD = 0x10; // TMOD=0001 000B,使用 T1 的方式1定时.
TH1 = f1(i); // 给 T1 高8位赋初值.
TL1 = f2(i); // 给 T1 低8位赋初值.
TR1 = 1; // 启动 T1
while(1) { // 循环等待
i = 460;
while(j < 2000);
j = 0;
i = 360;
while(j < 2000);
j = 0;
}
}
void T1_x(void) interrupt 3 using 0 { // 定时器 T1 中断函数
TR1 = 0; // 关闭 T1
sound = ~sound; // P1.7 输出求反
TH1 = f1(i); // T1 的高8位重新赋初值.
TL1 = f2(i); // T1 的低8位重新赋初值.
j++;
TR1 = 1; // 启动定时器 T1
}
二、LED数码管秒表的制作
电路图:
代码:
#include <reg51.h> //头文件
unsigned char code discode1[] = {0xbf, 0x86, 0xdb, 0xcf, 0xe6, 0xed, 0xfd, 0x87, 0xff, 0xef}; //数码管显示0~9的段码表, 带小数点
unsigned char code discode2[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; //数码管显示0~9的段码表,不带小数点
unsigned char timer = 0; //timer记录中断次数
unsigned char second; //second储存秒
unsigned char key = 0; //key记录按键次数
void int_T0() interrupt 1 using 0 //定时器T0中断函数
{
TR0 = 0; //停止计时,执行以下操作(会带来计时误差)
TH0 = 0xee; //向TH0写入初值的高8位
TL0 = 0x00; //向TL0写入初值的低8位,定时5ms
timer++; //记录中断次数
if (timer == 20) //中断20次,共计时20*5ms=100ms=0.1s
{
timer = 0; //中断次数清0
second++; //加0.1s
P0 = discode1[second / 10]; //根据计时,即时显示秒位
P2 = discode2[second % 10]; //根据计时,即时显示0.1s位
}
if (second == 99) //当计时到9.9s时
{
TR0 = 0; //停止计时
second = 0; //秒数清0
key = 2; //按键数置2,当再次按下按键时,key++,即key=3,秒表清0复原
}
else //计时不到9.9s时
{
TR0 = 1; //启动定时器继续计时
}
}
void main() //主函数
{
TMOD = 0x01; //定时器T0方式1定时
ET0 = 1; //允许定时器T0中断
EA = 1; //总中断允许
second = 0; //设初始值
P0 = discode1[second / 10]; //显示秒位0
P2 = discode2[second % 10]; //显示0.1s位0
while (1) //循环
{
if ((P3 & 0x80) == 0x00) //当按键被按下时
{
key++; //按键次数加1
switch (key) //根据按键次数分三种情况
{
case 1: //第一次按下为启动秒表计时
TH0 = 0xee; //向TH0写入初值的高8位
TL0 = 0x00; //向TL0写入初值的低8位,定时5ms
TR0 = 1; //启动定时器T0
break;
case 2: //按下两次暂定秒表
TR0 = 0; //关闭定时器T0
break;
case 3: //按下3次秒表清0
key = 0; //按键次数清0
second = 0; //秒表清0
P0 = discode1[second / 10]; //显示秒位0
P2 = discode2[second % 10]; //显示0.1s位0
break;
}
while ((P3 & 0x80) == 0x00); //如果按键时间过长在此循环
}
}
}
三、使用定时器实现一个LCD显示时钟
电路图:
代码:
#include <reg51.h>
#include <lcd1602.h>
#define uchar unsigned char
#define uint unsigned int
uchar int_time; //定义中断次数计数变量
uchar second; //秒计数变量
uchar minute; //分钟计数变量
uchar hour; //小时计数变量
uchar code date[] = " H.I.T. CHINA "; //LCD第1行显示的内容
uchar code time[] = " TIME 23:59:55 "; //LCD第2行显示的内容
void clock_init() {
uchar i, j;
for (i = 0; i < 16; i++) {
write_data(date[i]);
}
write_com(0x80 + 0x40);
for (j = 0; j < 16; j++) {
write_data(time[j]);
}
}
void clock_write(uint s, uint m, uint h) {
write_sfm(0x47, h);
write_sfm(0x4a, m);
write_sfm(0x4d, s);
}
void main() {
init1602(); //LCD初始化
clock_init(); //时钟初始化
TMOD = 0x01; //设置定时器T0为方式1定时
EA = 1; // 总中断开
ET0 = 1; // 允许T0中断
TH0 = (65536 - 46483) / 256; //给T0装初值
TL0 = (65536 - 46483) % 256;
TR0 = 1;
int_time = 0; //中断次数、秒、分、时单元清0
second = 55;
minute = 59;
hour = 23;
while (1) {
clock_write(second, minute, hour);
}
}
void T0_interserve(void) interrupt 1 using 1 //T0中断服务子程序
{
int_time++; //中断次数加1
if (int_time == 20) { //若中断次数计满20次
int_time = 0; //中断次数变量清0
second++; //秒计数变量加1
}
if (second == 60) { //若计满60s
second = 0; //秒计数变量清0
minute++; //分计数变量加1
}
if (minute == 60) { //若计满60分
minute = 0; //分计数变量清0
hour++; //小时计数变量加1
}
if (hour == 24) { //若计满24小时
hour = 0; //小时计数计满24,将小时计数变量清0
}
TH0 = (65536 - 46083) / 256; //定时器T0重新赋值
TL0 = (65536 - 46083) % 256;
}
四、甲乙两个单片机串口通信
电路图:
代码:
//甲机
#include <reg51.h>
#define uchar unsigned char
#define TR 0 // 定义TR,0为发送模式
// 发送的10个数据
uchar buf[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a};
uchar sum;
void delay(unsigned int i); // 延时函数声明
void init(void); // 初始化函数声明
void send(void); // 发送函数声明
void receive(void); // 接收函数声明
void main(void) {
init(); // 调用甲机串口初始化
if(TR == 0) { // TR=0,为发送模式
send(); // 调用发送函数
}
if(TR == 1) { // TR=1,为接收模式
receive(); // 调用接收函数
}
}
void delay(unsigned int i) {
unsigned char j;
for(; i > 0; i--) {
for(j = 0; j < 125; j++);
}
}
void init(void) {
TMOD = 0x20; // T1方式2定时
TH1 = 0xf4; // 波特率2400
TL1 = 0xf4;
PCON = 0x00; // SMOD=0
SCON = 0x50; // 串行口方式1,REN=1允许接收
TR1 = 1; // 启动T1
}
void send(void) {
uchar i;
do {
delay(1000);
SBUF = 0xaa; // 发送联络信号
while(TI == 0); // 等待数据发送完毕
TI = 0; // 清TI
while(RI == 0); // 等待乙机应答
RI = 0; // 清RI
} while(SBUF != 0xbb); // 乙机未准备好,继续联络
do {
sum = 0;
for(i = 0; i < 10; i++) {
delay(1000);
SBUF = buf[i]; // 向乙机发数据
sum += buf[i]; // 求校验和
while(TI == 0);
TI = 0; // 清TI
}
delay(1000);
SBUF = sum; // 发送校验和
while(TI == 0); TI = 0;
while(RI == 0); RI = 0;
} while(SBUF != 0x00); // 出错,重新发送
while(1);
}
void receive(void) {
uchar i;
RI = 0;
while(RI == 0); RI = 0;
while(SBUF != 0xaa); // 判断乙机是否发出请求
SBUF = 0xBB; // 发送应答信号
while(TI == 0); // 等待发送结束
TI = 0;
sum = 0;
for(i = 0; i < 10; i++) {
while(RI == 0); RI = 0; // 接收数据
buf[i] = SBUF; // 接收一个数据
sum += buf[i]; // 求校验和
}
while(RI == 0);
RI = 0; // 接收乙机的校验和
if(SBUF == sum) {
SBUF = 0x00; // 校验和相等,则发00H
} else {
SBUF = 0xFF; // 出错发FFH,重新接收
while(TI == 0); TI = 0;
}
}
//乙机
#include <reg51.h> // 乙机串行通信程序
#define uchar unsigned char
#define TR 1 // 接收、发送的区别值,TR=1,为接收
uchar idata buf[10] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A};
uchar sum; // 校验和
void delay(unsigned int i)
{
unsigned char j;
for(; i > 0; i--)
for(j = 0; j < 125; j++);
}
void init(void) // 乙机串口初始化函数
{
TMOD = 0x20; // T1方式2定时
TH1 = 0xF4; // 波特率2400
TL1 = 0xF4;
PCON = 0x00; // SMOD=0
SCON = 0x50; // 串行口方式1,REN=1允许接收
TR1 = 1; // 启动T1
}
void send(void) // 乙机发送函数
{
uchar i;
do {
SBUF = 0xAA; // 发送联络信号
while (TI == 0); // 等待数据发送完毕
TI = 0;
while (RI == 0); // 等待乙机应答
RI = 0;
} while (SBUF != 0xBB); // 乙机未准备好,继续联络
do {
sum = 0; // 校验和变量清0
for(i = 0; i < 10; i++) {
SBUF = buf[i];
sum += buf[i]; // 求校验和
while(TI == 0);
TI = 0;
}
SBUF = sum;
while(TI == 0); TI = 0;
while(RI == 0); RI = 0;
} while (SBUF != 0); // 出错,重新发送
}
void receive(void) // 乙机接收函数
{
uchar i;
RI = 0;
while (RI == 0); RI = 0;
while (SBUF != 0xAA) {
SBUF = 0xFF;
while (TI == 0);
TI = 0;
delay(1000);
} // 判甲机是否发出请求
SBUF = 0xBB; // 发送应答信号0xBB
while (TI == 0); // 等待发送结束
TI = 0;
sum = 0;
for(i = 0; i < 10; i++) {
while (RI == 0); RI = 0; // 接收数据
buf[i] = SBUF; // 接收一个数据
sum += buf[i]; // 求校验和
}
while (RI == 0); RI = 0; // 接收甲机的校验和
if (SBUF == sum) { // 比较校验和
SBUF = 0x00; // 校验和相等,则发00H
} else {
SBUF = 0xFF; // 出错发FFH,重新接收
while (TI == 0); TI = 0;
}
}
void main(void) // 乙机主程序
{
init(); // 初始化
if (TR == 0) { // TR=0,为发送
send(); // 调用发送函数
} else {
receive(); // 调用接收函数
}
}
五、将单片机串口与笔记本电脑串口模块相连,单片机每隔2秒发送“Hello C51”,笔记本电脑用串口助手软件接收
代码:
#include <REGX52.H>
#include "stdio.h"
unsigned char ch;
unsigned char Flag=1;
void Delay(unsigned int xms) //@11.0592MHz
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
}
void UartInit(void)
{
PCON &= 0x7F;
SCON = 0x50;
TMOD &= 0x0F;
TMOD |= 0x20;
TL1 = 0xFD;
TH1 = 0xFD;
ET1 = 0;
TR1 = 1;
EA=1;
ES=1;
}
void UartSend()
{
TI=1;
puts("Hello C51");
while(!TI);
TI=0;
Delay(2000);
}
void main()
{
UartInit();
while(1)
{
if(Flag==1)UartSend();
}
}
void UART_Routine() interrupt 4
{
if(RI==1)
{
RI=0;
ch=SBUF;
if(ch=='1')Flag=1;
if(ch=='0')Flag=0;
}
}