第7周作业---单片机定时器与串口通信

一、利用中断发出1Khz的方波信号,驱动蜂鸣器鸣叫

电路图:
![[Pasted image 20240411201422.png]]

代码:

#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数码管秒表的制作

电路图:
![[Pasted image 20240411211600.png]]

代码:

#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显示时钟

电路图:
![[Pasted image 20240411222617.png]]

代码:

#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;
}

四、甲乙两个单片机串口通信

电路图:
![[Pasted image 20240420153249.png]]

代码:

//甲机
#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;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值