单片机第1季:零基础学51单片机-串口通信和RS485\DS1302串口调试

学习目标:

1.通信的概念
2.串行通信
3.编程实践


学习内容:

1)通信的概念
什么是通信
(1)人和人之间的通信
(2)人和计算机之前的通信
(3)计算机和计算机之间的通信
通信的关键
(1)事先约定
(2)基本信息单元(bit K字节)
(3)有效信息的编码、传输和解码
通信的专业性概念
(1)同步和异步通信
(2)单工、半双工和全双工通信
(3)并行和串行通信
(4)电平信号和差分信号
2)串行通信
串口通信
(1)一种特定的通信协议()
(2)串行通信、串口通信、UART、USART
(3)异步、串行、全双工
串行通信的主要用途
(1)早期:计算机之间短距离通信(1.5米内),完备通信机制
(2)现在:CPU之间近距离通信、调试信息输入输出,非完备通信
串行通信的工作方式
(1)3根线(GND\RXD\TXD)
(2)发送方有发送移位寄存器,接收方有接收移位寄存器
(3)数据在发送方和接收方的CPU中以字节为单位整字节处理
(4)数据在通信线上以位为单位逐个bit的传输
串行通信的主要概念
(1)起始位、数据位(8位)、奇偶效验位、停止位 一帧
(2)波特率(串行通信的速度)(1秒钟传输多少个bit位)(发送、接收波特率一致)
(3)流控:速率协商,现在一般都禁用掉
3)编程实践
(1)采用串口读时间

/**
 * *********************************************
 * 
 * 8051 blink demo
 * 
 * PIN: P11
 * 
 * *********************************************
*/

#include "REG52.H"
#include <INTRINS.H>

sbit DSIO = P3 ^ 4;
sbit RST = P3 ^ 5;
sbit SCLK = P3 ^ 6;

//使用code可以把这个数组放在false中而不是RAM中
unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d };
unsigned char time[7];  //用来存储读取的时间的

void uart_init(void);
void uart_send_byte(unsigned char c);

void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}


//向ds1302的内部寄存器addr写入一个值value
void ds1302_write_reg(unsigned char addr,unsigned char value)
{
    unsigned char i = 0;
    unsigned char dat = 0;
    //第一部分:起始
    SCLK = 0;
    Delay1ms();	
    RST = 0;
    Delay1ms();
    RST = 1;    //SCLK为低时,RST由低变高,意味着一个大的周期的开始
       
    //第二部分:写入第一字节,addr
    for (i = 0; i < 8; i++)
    {
        dat = addr & 0x01; //SPI是从第一位开始传输的

        DSIO = dat;        //把要发送的bit数据丢到IO引脚上去准备好
        SCLK = 1;          //制造上升沿,让DS1302把IO上的值读走
        Delay1ms();        //读走之后,一个小周期就完成了
        SCLK = 0;          //把SCLK拉低,是为了给下一个周期做准备
        addr >>= 1;        //把addr右移一位
    }
    
    //第三部分:写入第二字节,value
    for (i = 0; i < 8; i++)
    {
        dat = value & 0x01; //SPI是从第一位开始传输的
        DSIO = dat;         //把要发送的bit数据丢到IO引脚上去准备好
        SCLK = 1;           //制造上升沿,让DS1302把IO上的值读走
        Delay1ms();         //读走之后,一个小周期就完成了
        SCLK = 0;           //把SCLK拉低,是为了给下一个周期做准备
        value >>= 1;         //把value右移一位
    }

    //第四部分:时序结束
    SCLK = 0;               //SCLK拉低为了后面的周期时初始状态是对的
    Delay1ms();
    RST = 0;                //RST拉低为了后面大周期的结束
    Delay1ms();
}
//向ds1302的内部寄存器addr读出一个值,作为返回值
unsigned char ds1302_read_reg(unsigned char addr)
{
    unsigned char i = 0;
    unsigned char dat = 0;  //用来存储读取到一字节数据的
    unsigned char tmp = 0;
    //第一部分:起始
    SCLK = 0;
    Delay1ms();	
    RST = 0;
    Delay1ms();
    RST = 1;    //SCLK为低时,RST由低变高,意味着一个大的周期的开始
       
    //第二部分:写入要读取的寄存器的地址,addr
    for (i = 0; i < 8; i++)
    {
        dat = addr & 0x01; //SPI是从第一位开始传输的

        DSIO = dat;        //把要发送的bit数据丢到IO引脚上去准备好
        SCLK = 1;          //制造上升沿,让DS1302把IO上的值读走
        Delay1ms();        //读走之后,一个小周期就完成了
        SCLK = 0;          //把SCLK拉低,是为了给下一个周期做准备
        addr >>= 1;        //把addr右移一位
    }
    
    //第三部分:写出一个字节DS1302返回给我们的值
    for (i = 0; i < 8; i++)
    {
        //在前面向ds1302写入addr的最后一个bit后,ds1302就会将读取到的寄存器
        //值的第一个bit放入IO引脚上,先读取在制造下降沿
        tmp = DSIO;
        dat |= ( tmp << i );
        SCLK = 1;           //由于上面SCLK是低,所以先拉高
        Delay1ms();         
        SCLK = 0;           //把SCLK拉低,制造一个下降沿
        Delay1ms();    


    }

    //第四部分:时序结束
    SCLK = 0;               //SCLK拉低为了后面的周期时初始状态是对的
    Delay1ms();
    RST = 0;                //RST拉低为了后面大周期的结束
    Delay1ms();
    
    //第五部分:解决读取时间是FF的问题
    DSIO = 0;
    
    return dat;
}
void ds1302_read_time()
{
    unsigned char i = 0;
    for(i=0; i<7; i++)
    {
        time[i] = ds1302_read_reg(READ_RTC_ADDR[i]);
    }
}
void debug_print_time(void)
{
    unsigned char i = 0;

    while(1)
    {
        //1.从ds1302读取时间
        ds1302_read_time();

        //2.for循环内打印一组7个时间
        for(i=0; i<7; i++)
        {
            uart_send_byte(time[i]);
        }

        //3.延时900ms后再继续下个周期
        Delay1ms();
    }
    
}
void main()
{
    unsigned char i = 0;
    uart_init();
    //测试串口工作
    // for(i=0; i<255; i++)
    // {
    //     uart_send_byte(i);
    //     Delay1ms();
    // }
    // ds1302_read_time();
    // uart_print_time();
    debug_print_time();

}

void uart_init(void)
{
	// 波特率9600
	SCON = 0x50;   	// 串口工作在模式1(8位串口)、允许接收
	PCON = 0x00;	// 波特率不加倍

	// 通信波特率相关的设置
	TMOD = 0x20;	// 设置T1为模式2
	TH1 = 253;
	TL1 = 253;	   	// 8位自动重装,意思就是TH1用完了之后下一个周期TL1会
					// 自动重装到TH1去

	TR1 = 1;		// 开启T1让它开始工作
	ES = 1;
	EA = 1;	
}
// 通过串口发送1个字节出去
void uart_send_byte(unsigned char c)
{
   // 第1步,发送一个字节
   SBUF = c;

   // 第2步,先确认串口发送部分没有在忙
   while (!TI);

   // 第3步,软件复位TI标志位
   TI = 0;
}

(2)写时间

/**
 * *********************************************
 * 
 * 8051 blink demo
 * 
 * PIN: P11
 * 
 * *********************************************
*/

#include "REG52.H"
#include <INTRINS.H>

sbit DSIO = P3 ^ 4;
sbit RST = P3 ^ 5;
sbit SCLK = P3 ^ 6;

//使用code可以把这个数组放在false中而不是RAM中
unsigned char code READ_RTC_ADDR[7] = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d };
unsigned char code WRITE_RTC_ADDR[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a,0x8c};
unsigned char time[7];  //用来存储读取的时间的

void uart_init(void);
void uart_send_byte(unsigned char c);

void Delay1ms()		//@11.0592MHz
{
	unsigned char i, j;

	_nop_();
	i = 2;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}


//向ds1302的内部寄存器addr写入一个值value
void ds1302_write_reg(unsigned char addr,unsigned char value)
{
    unsigned char i = 0;
    unsigned char dat = 0;
    //第一部分:起始
    SCLK = 0;
    Delay1ms();	
    RST = 0;
    Delay1ms();
    RST = 1;    //SCLK为低时,RST由低变高,意味着一个大的周期的开始
       
    //第二部分:写入第一字节,addr
    for (i = 0; i < 8; i++)
    {
        dat = addr & 0x01; //SPI是从第一位开始传输的

        DSIO = dat;        //把要发送的bit数据丢到IO引脚上去准备好
        SCLK = 1;          //制造上升沿,让DS1302把IO上的值读走
        Delay1ms();        //读走之后,一个小周期就完成了
        SCLK = 0;          //把SCLK拉低,是为了给下一个周期做准备
        addr >>= 1;        //把addr右移一位
    }
    
    //第三部分:写入第二字节,value
    for (i = 0; i < 8; i++)
    {
        dat = value & 0x01; //SPI是从第一位开始传输的
        DSIO = dat;         //把要发送的bit数据丢到IO引脚上去准备好
        SCLK = 1;           //制造上升沿,让DS1302把IO上的值读走
        Delay1ms();         //读走之后,一个小周期就完成了
        SCLK = 0;           //把SCLK拉低,是为了给下一个周期做准备
        value >>= 1;         //把value右移一位
    }

    //第四部分:时序结束
    SCLK = 0;               //SCLK拉低为了后面的周期时初始状态是对的
    Delay1ms();
    RST = 0;                //RST拉低为了后面大周期的结束
    Delay1ms();
}
//向ds1302的内部寄存器addr读出一个值,作为返回值
unsigned char ds1302_read_reg(unsigned char addr)
{
    unsigned char i = 0;
    unsigned char dat = 0;  //用来存储读取到一字节数据的
    unsigned char tmp = 0;
    //第一部分:起始
    SCLK = 0;
    Delay1ms();	
    RST = 0;
    Delay1ms();
    RST = 1;    //SCLK为低时,RST由低变高,意味着一个大的周期的开始
       
    //第二部分:写入要读取的寄存器的地址,addr
    for (i = 0; i < 8; i++)
    {
        dat = addr & 0x01; //SPI是从第一位开始传输的

        DSIO = dat;        //把要发送的bit数据丢到IO引脚上去准备好
        SCLK = 1;          //制造上升沿,让DS1302把IO上的值读走
        Delay1ms();        //读走之后,一个小周期就完成了
        SCLK = 0;          //把SCLK拉低,是为了给下一个周期做准备
        addr >>= 1;        //把addr右移一位
    }
    
    //第三部分:写出一个字节DS1302返回给我们的值
    for (i = 0; i < 8; i++)
    {
        //在前面向ds1302写入addr的最后一个bit后,ds1302就会将读取到的寄存器
        //值的第一个bit放入IO引脚上,先读取在制造下降沿
        tmp = DSIO;
        dat |= ( tmp << i );
        SCLK = 1;           //由于上面SCLK是低,所以先拉高
        Delay1ms();         
        SCLK = 0;           //把SCLK拉低,制造一个下降沿
        Delay1ms();    


    }

    //第四部分:时序结束
    SCLK = 0;               //SCLK拉低为了后面的周期时初始状态是对的
    Delay1ms();
    RST = 0;                //RST拉低为了后面大周期的结束
    Delay1ms();
    
    //第五部分:解决读取时间是FF的问题
    DSIO = 0;

    return dat;
}
void ds1302_read_time()
{
    unsigned char i = 0;
    for(i=0; i<7; i++)
    {
        time[i] = ds1302_read_reg(READ_RTC_ADDR[i]);
    }
}
void ds1302_write_time(void)
{
    unsigned char i = 0;
    //准备好要写入的时间
    time[0] = 0x24;   //对应24s
    time[1] = 0x39;   //对应39m
    time[2] = 0x11;   //对应11h
    time[3] = 0x06;   //对应6日
    time[4] = 0x12;   //对应11月
    time[5] = 0x02;   //对应星期2
    time[6] = 0x16;   //对应16年

    ds1302_write_reg(0x8E, 0x00);//去掉写保护
    for(i=0; i<7; i++)
    {
        ds1302_write_reg(WRITE_RTC_ADDR[i],time[i]);
    }
    ds1302_write_reg(0x8E, 0x80);//打开写保护
}
void debug_print_time(void)
{
    unsigned char i = 0;

    while(1)
    {
        //1.从ds1302读取时间
        ds1302_read_time();

        //2.for循环内打印一组7个时间
        for(i=0; i<7; i++)
        {
            uart_send_byte(time[i]);
        }

        //3.延时900ms后再继续下个周期
        Delay1ms();
    }
    
}
void main()
{
    //unsigned char i = 0;
    uart_init();
    ds1302_write_time();
    //测试串口工作
    // for(i=0; i<255; i++)
    // {
    //     uart_send_byte(i);
    //     Delay1ms();
    // }
    // ds1302_read_time();
    // uart_print_time();
    debug_print_time();

}

void uart_init(void)
{
	// 波特率9600
	SCON = 0x50;   	// 串口工作在模式1(8位串口)、允许接收
	PCON = 0x00;	// 波特率不加倍

	// 通信波特率相关的设置
	TMOD = 0x20;	// 设置T1为模式2
	TH1 = 253;
	TL1 = 253;	   	// 8位自动重装,意思就是TH1用完了之后下一个周期TL1会
					// 自动重装到TH1去

	TR1 = 1;		// 开启T1让它开始工作
	ES = 1;
	EA = 1;	
}
// 通过串口发送1个字节出去
void uart_send_byte(unsigned char c)
{
   // 第1步,发送一个字节
   SBUF = c;

   // 第2步,先确认串口发送部分没有在忙
   while (!TI);

   // 第3步,软件复位TI标志位
   TI = 0;
}


学习时间:

提示:这里可以添加计划学习的时间

例如:

  • 周一至周五晚上 7 点—晚上9点
  • 周六上午 9 点-上午 11 点
  • 周日下午 3 点-下午 6 点

学习产出:

提示:这里统计学习计划的总量

例如:

  • 技术笔记 2 遍
  • CSDN 技术博客 3 篇
  • 习的 vlog 视频 1 个
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值