这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » 【原创】蓝桥杯单片机组第十届国赛程序题分享--from恶龙咆哮

共10条 1/1 1 跳转至

【原创】蓝桥杯单片机组第十届国赛程序题分享--from恶龙咆哮

工程师
2022-06-30 16:58:22     打赏

今天和大家分享一下2019年第十届蓝桥杯单片机决赛的程序题,我在做这道题的时候属实有被难到,今天就和大家分享一下;先看题目:

4、功能描述

4.1功能概述

1)使用超声波测距单元完成测距功能。

2) 通过DS18B20温度传感器完成温度测量功能。

3)通过 PCF8591 D/A 转换芯片完成模拟电压输出功能。

4)通过AT24C02E2PROM存储器完成参数变动次数记录功能。

5)通过竞赛板上的USB 转串口模块实现串口收发功能。

6) 通过键盘、数码管、LED指示灯等完成人机交互操作。

7) 温度(T)、 距离(S)测量结果刷新时间要求

●温度(T)≤0.5秒。

距离(S)≤1秒。

8)距离(S)测量说明

测量范围要求: 10cm - 50cm。

●声音在空气中的传播速度: 340米/秒。

4.2显示功能

1) 数据界面

一 温度数据显示

温度数据界面如图2所示.显示内容包括提示符C和温度值。温度数据单位为摄氏度C,数据保留小数点后两位有效数字,占用4位数码管。

1.png

距高数据显示

距离数据界面如图3所示,显示内容包括提示符L和距离数据。距离数据单位为cm,可显示距离范围0cm-99cm,占用两位数码管。

2.png

变更次数显示

显示内容包括提示符n和参数变动次数。参数变动次数记录范围为0-65535次,占用5位数码管,数据长度不足5位时,高位数码管熄灭。

3.png

2) 参数界面

●温度参数

显示内容包括提示符P、参数编号l和温度参数,温度参数可调整范围0-99。

4.png

距离参数

显示内容包括提示符只、参数编号2和距离参数,距离参数可调整范围0-99。

5.png

好,所有的显示功能都已经在这里了,那么我们就先把这些显示功能的函数写下来,在写显示函数之前,我们要先把准备工作做好,比如关闭继电器、蜂鸣器等,准备好数码管的段选数组:

typedef unsigned int u16;
typedef unsigned char u8;
 
u8 code smgduan[17]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
            0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//共阴显示0~F的值
 
 
void delayms(u16 i)                                           //延迟函数
{
    u16 aa;
    while(i--)
    {
        for(aa=0;aa<845;aa++);
    }
}
                   
void InitHC138(u8 add)                         //Y4、Y5、Y6、Y7通道选择函数
{
    switch(add)
    {
        case(4):
            P2 = ( P2 & 0X1F ) | 0X80;break;
        case(5):
            P2 = ( P2 & 0X1F ) | 0Xa0;break;
        case(6):
            P2 = ( P2 & 0X1F ) | 0Xc0;break;
        case(7):
            P2 = ( P2 & 0X1F ) | 0Xe0;break;
    }
}
 
void InitHC573() //关闭蜂鸣器、继电器、LED函数
{
    InitHC138(5);
    P0 = 0X00;
    InitHC138(4);
    P0 = 0XFF;
}
 
void DigDisplay(u8 add,u8 dat) //数码管段选、位选函数
{
    InitHC138(6);
    P0 = 0X01 << add;
    InitHC138(7);
    P0 = dat;
}
void GetDatPro()                           //温度获取
{
    
    distance_get = distance;
    temp_get = Tempget();
    temp_get = temp_get*100;
    
}
 
void wave_rec(void)                      //超声波距离获取
{
    
    u8 num = 10;
    TX = 0;
    TL0 = 0xF4;     //设置定时初值
    TH0 = 0xFF;     //设置定时初值
    TR0 = 1;        //定时器0打开
    while(num--)
    {
        while(!TF0);
        TF0 = 0;
        TX ^= 1;
    }
    TR0 = 0;        //定时器0关闭
    TL0 = 0;        //设置定时初值
    TH0 = 0;        //设置定时初值
    TR0 = 1;        //定时器0打开
    while(RX && !TF0);
    TR0 = 0;
    if(TF0)
    {
        TF0 = 0;
        distance = 99;
    }
    else
    {
        distance = ((TH0 << 8) | TL0) * 0.017;
        if(distance > 99) distance = 99;
    }
}

好,准备工作做好后,就先把显示函数写出来:

u16 distance_get,distance_setup = 35;//定义距离变量和参数
u16 temp_get ,temp_setup = 30;       //定义温度变量和参数
u8 setup_count;                     //设置参数
//===================温度数据显示========================
void DisplayTempGet()
{
    DigDisplay(0,~smgduan[12]);
    delayms(1);
    DigDisplay(4,~smgduan[temp_get/1000]);
    delayms(1);
    DigDisplay(5,~(smgduan[temp_get/100%10] | 0x80));
    delayms(1);
    DigDisplay(6,~smgduan[temp_get/10%10]);
    delayms(1);
    DigDisplay(7,~smgduan[temp_get%10]);
    delayms(1);
}
 
//===================距离数据显示========================
void DisplayDistanceGet()
{
    DigDisplay(0,0xc7);
    delayms(1);
    DigDisplay(6,~smgduan[distance_get/10]);
    delayms(1);
    DigDisplay(7,~smgduan[distance_get%10]);
    delayms(1);
}
 
//===================参数数据变动显示========================
void DisplaySetupCount()
{
    DigDisplay(0,0xc8);
    delayms(1);
    
    DigDisplay(7,~smgduan[setup_count%10]);
    delayms(1);
    
  if(setup_count>9)
    {
        
        DigDisplay(6,~smgduan[setup_count/10%10]);
        delayms(1);
    }
    if(setup_count>99)
    {
        DigDisplay(5,~smgduan[setup_count/100%10]);
        delayms(1);
    }
    if(setup_count>999)
    {
        DigDisplay(4,~smgduan[setup_count/1000%10]);
        delayms(1);
    }
    if(setup_count>9999)
    {
        DigDisplay(3,~smgduan[setup_count/10000]);
        delayms(1);
    }
}
 
//===================温度参数显示========================
void DisplayTempSetup()
{
    DigDisplay(0,0x8c);
    delayms(1);
    DigDisplay(3,~smgduan[1]);
    delayms(1);
    DigDisplay(6,~smgduan[temp_setup/10]);
    delayms(1);
    DigDisplay(7,~smgduan[temp_setup%10]);
    delayms(1);
}
 
//===================距离参数显示========================
void DisplayDistanceSetup()
{
    DigDisplay(0,0x8c);
    delayms(1);
    DigDisplay(3,~smgduan[2]);
    delayms(1);
    DigDisplay(6,~smgduan[distance_setup/10]);
    delayms(1);
    DigDisplay(7,~smgduan[distance_setup%10]);
    delayms(1);
}

接下来,我们来看按键模块:
4.3
按键功能

1) “短按键”功能说明

●S13:定义为“界面”按键,按下SI3按键,切换数据界面和参数界面,按键S13切换模式如下图所示:

6.png

界面切换要求:

1)每次从数据界面进入参数界面,默认当前为温度参数。2)每次从参数界面进入数据界面,默认当前为温度数据。.

●S12:定义为“切换”按键。

在数据界面下,按下S12按键,切换显示温度数据、距离数据和参数变更次数。切换模式如下图所示:

7.png

在参数界面下,按下SI2按键,切换显示温度参数和距离参数,切换模式如下图所示:

8.png

●S16: 定义为“减”按键。

在温度参数界面下,按下S16,温度参数减少2℃.

在距离参数界面下,按下S16,距离参数减少5cm

●S17: 定义为“加”按键。

在温度参数界面下,按下S17,温度参数增加2℃。

2)“长按键” 功能说明

●任何界面状态下,长按S12按键,可重置参数变动次数记录为0次。

任何界面状态下,长按S13按键,可切换DAC输出功能,详见4. 6 DAC输出功能。 切换模式如下图所示:

9.png

3) 其它要求

长按键功能触发时间要求:按键按下时间超过1秒,触发长按键功能,否则为短按键。

按键应做好消抖处理,避免出现一次按键功能多次触发等问题。按键长按、短按对应的功能和效果不可互相影响。

请严格按照以上要求,定义各按键长按、短按功能。

这个按键是阉割版的矩阵按键,比较好处理,功能要求看起来似乎有点复杂,其实,只要我们把他们的逻辑写出来就会一目了然,S13只有一个切换功能,我们就用位定义一个变量,只有0和1两个状态,再设几个变量,每当按键按下,只是变量的值在变,不要再按键处理函数里调用显示函数,这样太乱:

void KeyScan()    
{
    R1 = 0;
    R2 = 1;
    C1 = 1;C2 = 1;
    if(C1 == 0)      //S13
    {
        if(turn_dat_setup == 0) //数据界面
        {
            get_dat++;
        }
        else if(turn_dat_setup == 1)
        {
            setup_dat++;
        }
        DA_flag = 1;
        while(!C1);
        DA_flag = 0;
    }
    
    
    else if(C2 == 0)  //S17
    {
        switch(setup_dat)
        {
            case(1):temp_setup = temp_setup+2;break;
            case(2):distance_setup = distance_setup+5;break;          
        }
        setup_count++;
        while(!C2);
    }
    
    R2 = 0;
    R1 = 1;
    C1 = 1;C2 = 1;
    if(C1 == 0)      //S12
    {
        turn_dat_setup = ~turn_dat_setup;
        
        count_flag = 1;
        while(!C1);
        count_flag = 0;
        EEPROM_write(0x01,setup_count/256);
        delayms(5);
        EEPROM_write(0x02,setup_count%256);
        delayms(5);
    }
    
    
    else if(C2 == 0)  //S16
    {
        switch(setup_dat)
        {
            case(1):temp_setup = temp_setup-2;break;
            case(2):distance_setup = distance_setup-5;break;          
        }
        setup_count++;
        while(!C2);
    }
}
 
void DisplayDat()                           //对于按键控制的参数进行显示
{
    if(turn_dat_setup == 0)
    {
        switch(get_dat)
        {
            case(1):DisplayTempGet();break;
            case(2):DisplayDistanceGet();break;
            case(3):DisplaySetupCount();break;
        }
    }
    else if(turn_dat_setup == 1)
    {
        switch(setup_dat)
        {
            case(1):DisplayTempSetup();break;
            case(2):DisplayDistanceSetup();break;
        }
    }
}
 
void SetupDatPro()                     //数据的边界范围处理
{
    if(get_dat > 3)
    {
        get_dat = 1;
    }
    if(get_dat < 1)
    {
        get_dat = 3;
    }
    
    if(setup_dat > 2)
    {
        setup_dat = 1;
    }
    if(setup_dat < 1)
    {
        setup_dat = 2;
    }
    
    if(temp_setup > 99)
    {
        temp_setup = 0;
    }
    if(temp_setup < 0)
    {
        temp_setup = 99;
    }
    
    if(distance_setup > 99)
    {
        distance_setup = 0;
    }
    if(distance_setup < 0)
    {
        distance_setup = 99;
    }
}
 
void Timer2() interrupt 12             //这个是定时器2,我们后面会讨论到
{
    u16 count_sec_setup,count_sec_AD;   
    if (DA_flag)                       //长按键 DA切换
    {
        count_sec_AD++;
        if(count_sec_AD == 500)
        {
            count_sec_AD = 0;
            DA_turn = ~DA_turn;
 
        }
    }
    if(count_flag == 1)             //长按键清零     
    {
        count_sec_setup++;
        if(count_sec_setup == 500)
        {
            setup_count = 0;
            count_sec_setup = 0;
        }
    }
}

4.4存储功能

1)数据的存储

每当一次参数设置操作完成(从参数界面退出,切换回数据界面),如果参
数发生变化,参数变动次数加1,将参数变动次数保存在E2RPOM存储器,要求可记录范围: 0-65535.

2)数据的重置.

参数变动次数可以通过长按S12重置为0次。
存储功能也已经写在按键扫描函数里了;这个是读取函数:

void GetSetupCount()                           //读取EEPROM的数值
{
    u16 count_h,count_l;
    count_h = EEPROM_read(0x01);
    count_l = EEPROM_read(0x02);
    setup_count = ((count_h * 256) + count_l);
}

4.5串口功能

1)通信模式

波特率: 4800 bps

校验位:无校验

停止位: 1位。

2)数据召测功能

通过串口调试软件下发数据召测指令,设备接收到正确指令后,上报数据或参数。召测指令格式要求如下:

①查询数据指令:"ST\r\n”, 接收到指令后,设备返回距离和温度数据,数据格式要求如下:

以字符串形式输出,以’$’开头, "\r\n”结尾。

距离数据(S)和温度数据(T)以’,’间隔。

-格式: $距离数据,温度数据\r\n,

举例: $20,24. 32\r\n

上报的距离数据为整数,温度数据保留小数点后两位有效数字。

②查询参数指令: ”PARA\r\n”,接收到指令后,设备返回当前的距离参数和温度参数。返回数据格式要求如下:

以字符串形式输出,以‘$’开头,” r\n”结尾。

距离参数(S)和温度参数(T)以’,’间隔。

格式: #距离参数,温度参数\r\n

~举例: #35,30\r\n

如设备接收到错误指令,返回”ERROR\r\n”。

备注:

1) 串口查询参数、数据指令响应时间要求: ≤500ms。

2) 串口逻辑功能错乱,发送乱码、错误数据将被酌情扣分。

3) S12、 S13、 S16、 S17按键扫描过程和串口通讯功能应互不影响。
串口这一模块我一直觉得是最难的一块,因为总是不能够顺畅的打开PC和单片机之间的通信。而这道题的难点在于,超声波已经占据一个定时器资源了,我们还需要一个定时器进行定时工作,这个时候就需要打开第三个定时器了,对于第三个定时器,我们使用的<reg52>的头文件没有包含相关的寄存器,需要我们查阅资料进行配置:

sfr T2H = 0xD6;  //定时器2的高八位寄存器
sfr T2L = 0xD7;  //定时器2的低八位寄存器
sfr AUXR = 0X8E;               
sfr T2MOD = 0XC9;
sfr IE2 = 0XAF;
 
u8 RevBuf[20]; //数据接收缓冲区
 
bit rx_flag;
bit send_enable = 0;     //发送标志位
 
u8 rx_tt;                 //
u8 rx_cnt;
 
void UartInit(void)    //4800bps@12.000MHz
{
 
    SCON = 0x50;       //8位数据,可变波特率
    AUXR |= 0x40;      //定时器1时钟为Fosc,即1T
    AUXR &= 0xFE;      //串口1选择定时器1为波特率发生器
    TMOD &= 0x0F;      //设定定时器1为16位自动重装方式
    TL1 = 0x8F;     //设定定时初值
    TH1 = 0xFD;     //设定定时初值
    ET1 = 0;        //禁止定时器1中断
    TR1 = 1;        //启动定时器1
    ES = 1;
}
void Time2Init()    //定时器2打开
{
    EA = 1;
    IE2 = (1<<2);
    AUXR &= 0XFB;
    T2L = 0X30;              //2ms
    T2H = 0XF8;
    AUXR |= 0X10;
}
void SendByte(u8 dat)         //串口发送字节
{
    SBUF = dat;
    while(!TI);
    TI = 0;
}
 
void SendDat(u8 *str)          //串口一位一位的发送需要发送的数据
{
    while(*str != '\0')
    {
        SendByte(*str++);
    }
}
 
void Urat() interrupt 4       //串口接收,接收到的数据暂存缓冲区数组中
{
    if(RI == 1)
    {
        RI = 0;
        rx_flag = 1;                 //表示数据已经接收完毕
        RevBuf[rx_cnt++] = SBUF;     // 放入暂存区
    }
}
 
void UratPro()
{
    if(send_enable)                  //允许向PC发送数据
    {
        send_enable = 0;
        SendDat(RevBuf);
    }
     
}
 
void Timer2() interrupt 12 
{   
    if(rx_flag && ++rx_tt >= 50)           //如果数据接收完毕
    {
        rx_flag = 0;
        rx_tt = 0;
        RevBuf[rx_cnt++] = '\0';
        rx_cnt = 0;
        
        if(strcmp(RevBuf,"ST\r\n") == 0)  //判断电脑发送的信息是否一致,如
        {                                 //果一致,发送距离数据
            send_enable = 1;
            sprintf(RevBuf,"$%d,%d\r\n",distance_get,temp_get%100);
        }
        else if(strcmp(RevBuf,"PARA\r\n") == 0)
        {
            send_enable = 1;
            sprintf(RevBuf,"$%d,%d\r\n",distance_setup,temp_setup);
        }
        else
        {
            send_enable = 1;
            sprintf(RevBuf,"ERROR\r\n");
        }
    }
}

4.6DAC输出功能

1) 在启动状态下,DAC输出电压值Vout取决于测距数据(S), 对应关系如下表所示

10.png

2)在停止状态下,DAC 固定输出0. 4V.
DAC功能看起来比较生疏,但其实将底层驱动完善后只用进行一个简单的判断就可以输出了:

void DAPro()     
{
    if(DA_turn == 1)
    {
        if(distance_get <= distance_setup)
        {
            DA_write(102);
        }
        else if(distance_get > distance_setup)
        {
            DA_write(204);
        }
    }
}

4. 7LED指示灯功能

1) 温度指示灯

当温度数据超过温度参数时,指示灯L1点亮,否则熄灭。

2) 距离指示灯

当距离数据小于距离参数时,指示灯L2点亮,否则熄灭。

3)DAC功能指示灯

启动状态下,指示灯L3点亮,停止状态下,指示灯L3熄灭。
每一次试题的最后都要考到LED和蜂鸣器之类的控制,做到这里的时候一定要静下心,必要的时候在纸上写一个逻辑框图就很清晰了:

void LedPro()
{     
    InitHC138(4);
    P0 = 0XFF;
    if(temp_get > temp_setup )
    {
        L1 = 0;
    }else L1 = 1;
    if(distance_get < temp_setup)
    {
        L2 = 0;
    }else L2 = 1;
    if(DA_turn == 1)
    {
        L3 = 0;
    }else L3 = 1;
    
}

4)本试题未涉及的 LED指示灯应处于熄灭状态,不同功能的指示灯状态切换时应互不影响。

1. 8初始状态说明

请严格按照以下要求设计作品的上电初始状态。

1) DAC处于启动状态。

2) 作品上电后。未经任何操作的状态下,数码管处于数据界面下,显示温度

3) 工作参数在每次上电时重置为默认值。

●温度参数: 30℃

●距离参数: 35cm

最后,我们写一个主函数,把核心的函数全部放进去:

void main()
{      
    InitHC573();
    Timer0Init();
    UartInit();
    GetSetupCount();
    Time2Init();
    InitHC138(4);
    P0 = 0XFF;
    while(1)
    {
        wave_rec();
        DisplayDat();
        KeyScan();
        SetupDatPro();
        GetDatPro();
        UratPro();
        DAPro();
        LedPro();
    }
}

在这里,给大家附上完善过的底层驱动代码以供大家参考:

//=======================================================================//
//==========================温度读取底层驱动============================//
//=====================================================================//
#include "onewire.h"
 
/****************************单总线延时函数****************************/
void Delay_OneWire(unsigned int t)
{
    unsigned char aa;
  while(t--)
    {
        for(aa=0;aa<10;aa++);
    }
}
 
/****************************DS18B20芯片初始化****************************/
bit Init_DS18B20(void)
{
    bit initflag = 0;
    DQ = 1;
    Delay_OneWire(12);
    DQ = 0;
    Delay_OneWire(80); 
    DQ = 1;
    Delay_OneWire(10); 
    initflag = DQ;    
    Delay_OneWire(5);
  
    return initflag;
}
 
 
/*******************通过单总线向DS18B20写一个字节****************/
void Write_DS18B20(unsigned char dat)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        DQ = 0;
        DQ = dat&0x01;
        Delay_OneWire(5);
        DQ = 1;
        dat >>= 1;
    }
    Delay_OneWire(5);
}
 
 
/****************************从DS18B20读取一个字节***********************/
unsigned char Read_DS18B20(void)
{
    unsigned char i;
    unsigned char dat;
  
    for(i=0;i<8;i++)
    {
        DQ = 0;
        dat >>= 1;
        DQ = 1;
        if(DQ)
        {
            dat |= 0x80;
        }       
        Delay_OneWire(5);
    }
    return dat;
}
 
 
/****************************温度读取处理函数****************************/
unsigned char Tempget()
{
    unsigned char low,high,temp;
     Init_DS18B20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0x44);
    Delay_OneWire(20);
 
     Init_DS18B20();
    Write_DS18B20(0xcc);
    Write_DS18B20(0xbe);
    
    low=Read_DS18B20();
    high=Read_DS18B20();
 
    temp=high<<4;
    temp|=(low>>4);
 
    return temp;
}
 
//======================================================================//
//==========================EEPROM底层驱动=============================//
//=====================================================================//
#include <REG52.H>
#include "intrins.h"
#include "iic.h"
 
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}    
 
 
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
 
//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */
 
 
void DA_write(uchar dat)
{
   IIC_Start();
   IIC_SendByte(0x90);
   IIC_WaitAck();
   IIC_SendByte(0x43);
   IIC_WaitAck();
   IIC_SendByte(dat);
   IIC_WaitAck();
    IIC_Stop(); 
}
 
uchar  AD_read(uchar add)
{
    uchar temp;
      IIC_Start();
      IIC_SendByte(0x90);
    IIC_WaitAck();
      IIC_SendByte(add);
    IIC_WaitAck();
      IIC_Stop(); 
 
    IIC_Start();
      IIC_SendByte(0x91);
    IIC_WaitAck();
      temp=IIC_RecByte();
      IIC_Stop(); 
    return temp;
 
}   
    
    
uchar  EEPROM_read(uchar add)
{
    uchar temp;
      IIC_Start();
      IIC_SendByte(0xA0);
    IIC_WaitAck();
      IIC_SendByte(add);
    IIC_WaitAck();
      IIC_Stop(); 
 
    IIC_Start();
      IIC_SendByte(0xA1);
    IIC_WaitAck();
      temp=IIC_RecByte();
      IIC_Stop(); 
    return temp;
 
 
}   
    
void  EEPROM_write(uchar add,uchar dat)
{
      IIC_Start();
      IIC_SendByte(0xA0);
    IIC_WaitAck();
      IIC_SendByte(add);
    IIC_WaitAck();
      IIC_SendByte(dat);
      IIC_WaitAck();
      IIC_Stop();    
}   
 
    
    
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    somenop;
    SDA = 0;
    somenop;
    SCL = 0;    
}
 
//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    somenop;
    SDA = 1;
}
 
 
 
//等待应答
bit IIC_WaitAck(void)
{
    SDA = 1;
    somenop;
    SCL = 1;
    somenop;
    if(SDA)    
    {   
        SCL = 0;
        IIC_Stop();
        return 0;
    }
    else  
    { 
        SCL = 0;
        return 1;
    }
}
 
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {   
        if(byt&0x80) 
        {   
            SDA = 1;
        }
        else 
        {
            SDA = 0;
        }
        somenop;
        SCL = 1;
        byt <<= 1;
        somenop;
        SCL = 0;
    }
}
 
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char da;
    unsigned char i;
    
    for(i=0;i<8;i++)
    {   
        SCL = 1;
        somenop;
        da <<= 1;
        if(SDA) 
        da |= 0x01;
        SCL = 0;
        somenop;
    }
    return da;
}
 
//======================================================================//
//==========================DS1302时钟底层驱动=========================//
//=====================================================================//
#include "ds1302.h"
 
//---DS1302写入和读取时分秒的地址命令---//
//---秒分时日月周年 最低位读写位;-------//
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};
 
//---DS1302时钟初始化2016年5月7日星期六23点59分50秒。---//
//---存储顺序是秒分时日月周年,存储格式是用BCD码---//
unsigned char TIME[7] = {50, 59, 23, 0x07, 0x05, 0x06, 0x16};
 
//从DS1302寄存器读出数据
unsigned char read(unsigned char add)
{
    unsigned char i,temp;
    unsigned char dat1,dat2;
    CE=0;
    SCLK=0;
    CE=1;
    writebyte(add);
    for(i=0;i<8;i++)
    {
        SCLK=0;
        temp>>=1;
        if(IO)
        {
            temp|=0x80;
        }
        SCLK=1;
    }
    
    IO=0;
    
    dat1=temp/16;//0XFF 1111 1111
    dat2=temp%16;
    
    temp=dat1*10+dat2;
    
    return temp;
}
 
//写字节
void writebyte(unsigned char dat)
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        SCLK=0;
        IO=dat&0x01;
        SCLK=1;
        dat>>=1;
    }
}
 
//向DS1302寄存器写入数据
void write(unsigned char add,unsigned char dat)
{
    unsigned char num;
    CE=0;
    SCLK=0;
    CE=1;
    writebyte(add);
    num=(dat/10<<4)|(dat%10);// 55
    writebyte(num);
    CE=0;
}
 
 
void Init_DS1302()
{
    unsigned char i;
    write(0x8e,0x00);
    for(i=0;i<7;i++)
    {
        write(WRITE_RTC_ADDR[i],TIME[i]);
    }
    write(0x8e,0x80);
    
}
void readtime()
{
    unsigned char i;
    write(0x8e,0x00);
    for(i=0;i<7;i++)
    {
        TIME[i]=read(READ_RTC_ADDR[i]);
    }
    write(0x8e,0x80);  
}




专家
2022-06-30 17:12:44     打赏
2楼

感谢分享


专家
2022-07-01 08:29:53     打赏
3楼

好资料,学习了。


专家
2022-07-01 08:41:08     打赏
4楼

学习


助工
2022-07-01 08:53:44     打赏
5楼

感谢分享


助工
2022-07-01 08:53:59     打赏
6楼

感谢分享


专家
2022-07-01 09:03:20     打赏
7楼

谢谢分享,学习


院士
2022-07-01 09:08:30     打赏
8楼

谢谢分享


高工
2022-07-01 14:09:04     打赏
9楼

谢谢分享


菜鸟
2022-07-01 14:41:04     打赏
10楼

感谢分享


共10条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]