蓝桥杯2024/1/21笔记---DS1302

本文介绍了在创建工程文件结构时,如何编写底层驱动函数,包括初始化、LED控制、按键检测、数码管显示以及使用DS1302时钟模块。还展示了如何利用定时器0进行中断服务,实现实时功能更新。
摘要由CSDN通过智能技术生成

每次建好工程文件夹,里边包含User(放工程文件,mian.c,可以在这里写如同我这个文章的文本文档)、Driver(存放底层文件如Led.c,Led.h等)
新建的工程先搭建框架,可以先书写底层函数(此次书写了五个函数并包含相应的头文件共十个底层文件)


底层函数内容:

1.初始化底层驱动专用文件


比如先用3个IO口控制74HC138译码器,控制Y4为低电平;当Y4为低电平时,或非门74HC02控制Y4C为高电平,使74HC573的OE端口有效,OE端口有效时,可使用P0口控制LED的亮灭。
可以去多了解74HC138译码器,74HC02或非门,74HC573八路输出透明锁存器的相关内容会更好理解
#include <Init.h>

//关闭外设
void System_Init()
{
    P0 = 0xff;
    P2 = P2 & 0x1f | 0x80;
    P2 &= 0x1f;
    P0 = 0x00;
    P2 = P2 & 0x1f | 0xa0;
    P2 &= 0x1f;
}
//头文件
#include <STC15F2K60S2.H>
void System_Init();

2.Led底层驱动专用文件


与初始化底层驱动专用文件同理,需要了解对应的锁存器控制,可以在使用的芯片数据手册查看
#include <Led.h>

void Led_Disp(unsigned char addr,enable)
{
    static unsigned char temp = 0x00;
    static unsigned char temp_old = 0xff;
    if(enable)
        temp |= 0x01 << addr;
    else
        temp &= ~(0x01 << addr);
    if(temp != temp_old)
    {
        P0 = ~temp;
        P2 = P2 & 0x1f |0x80;
        P2 &= 0x1f;
        temp_old = temp;
    }
}
//头文件
#include <STC15F2K60S2.H>
void Led_Disp(unsigned char addr,enable);

3.按键底层驱动专用文件


(板子上的按键从按键4开始到按键19,可根据实际硬件修改)
#include <Key.h>

unsigned char Key_Read()
{
    unsigned char temp = 0;
    P44 = 0; P42 = 1; P35 = 1; P34 = 1;
    if(P33 == 0) temp = 4;
    if(P32 == 0) temp = 5;
    if(P31 == 0) temp = 6;
    if(P30 == 0) temp = 7;
    P44 = 1; P42 = 0; P35 = 1; P34 = 1;
    if(P33 == 0) temp = 8;
    if(P32 == 0) temp = 9;
    if(P31 == 0) temp = 10;
    if(P30 == 0) temp = 11;
    P44 = 1; P42 = 1; P35 = 0; P34 = 1;
    if(P33 == 0) temp = 12;
    if(P32 == 0) temp = 13;
    if(P31 == 0) temp = 14;
    if(P30 == 0) temp = 15;
    P44 = 1; P42 = 1; P35 = 1; P34 = 0;
    if(P33 == 0) temp = 16;
    if(P32 == 0) temp = 17;
    if(P31 == 0) temp = 18;
    if(P30 == 0) temp = 19;
    return temp;
}
//头文件
#include <STC15F2K60S2.H>

unsigned char Key_Read();

4.数码管底层驱动专用文件


#include <Seg.h>

unsigned char Seg_Dula[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};//数码管段码储存数组
unsigned char Seg_Wela[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//数码管位码储存数组

void Seg_Disp(unsigned char wela,dula,point)
{
    P0 = 0xff; //
    P2 = P2 & 0x1f |0xe0;
    P2 &= 0x1f;
    P0 = Seg_Wela[wela];
    P2 = P2 & 0x1f |0xc0;
    P2 &= 0x1f;
    P0 = Seg_Dula[dula];
    if(point)
        P0 &= 0x7f;
    P2 = P2 & 0x1f |0xe0;
    P2 &= 0x1f;
}
//头文件
#include <STC15F2K60S2.H>

void Seg_Disp(unsigned char wela,dula,point);

5.时钟专用文件(官方给的底层驱动代码,时钟用BCD码的形式读取数据)


#include "ds1302.h"                                      
#include <reg52.h>//预定义函数
#include <intrins.h>

sbit SCK = P1^7;        
sbit SDA = P2^3;        
sbit RST = P1^3; 


//写字节


void Write_Ds1302(unsigned  char temp) 
{
    unsigned char i;
    for (i=0;i<8;i++)         
    { 
        SCK = 0;
        SDA = temp&0x01;
        temp>>=1; 
        SCK=1;
    }
}   

//向DS1302寄存器写入数据


void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
     RST=0;    _nop_();//RST=0;_nop_();这个RST是给时序状态,此处为拉低;nop的为等待,相当于延时
     SCK=0;    _nop_();
     RST=1;     _nop_();  
     Write_Ds1302(address);    
     Write_Ds1302(dat);        
     RST=0; 
}

//从DS1302寄存器读出数据


unsigned char Read_Ds1302_Byte ( unsigned char address )
{
     unsigned char i,temp=0x00;
     RST=0;    _nop_();
     SCK=0;    _nop_();
     RST=1;    _nop_();
     Write_Ds1302(address);
     for (i=0;i<8;i++)     
     {        
        SCK=0;
        temp>>=1;    
         if(SDA)
         temp|=0x80;    
         SCK=1;
    } 
     RST=0;    _nop_();
     SCK=0;    _nop_();
    SCK=1;    _nop_();
    SDA=0;    _nop_();
    SDA=1;    _nop_();
    return (temp);            
}

void Set_Rtc(unsigned char* ucRtc)//unsigned char* ucRtc指向我存放时分秒的数组指针
{
    unsigned char i;
    Write_Ds1302_Byte(0x8e,0x00);
    for(i=0;i<3;i++)//这个for循环可以使用下面这种方式会更为简单一些
        Write_Ds1302_Byte(0x84-2*i,ucRtc[i]);
//    Write_Ds1302_Byte(0x84,ucRtc[0]);//时
//    Write_Ds1302_Byte(0x82,ucRtc[1]);//分
//    Write_Ds1302_Byte(0x80,ucRtc[2]);//秒
    Write_Ds1302_Byte(0x8e,0x80);
    
}

void Read_Rtc(unsigned char* ucRtc)
{
    unsigned char i;
    for(i=0;i<3;i++)
        ucRtc[i] = Read_Ds1302_Byte(0x85-2*i);
}


//头文件


#ifndef __DS1302_H
#define __DS1302_H

//#include <reg52.h>//预定义函数,这些先添加到.c文件中预防报错
//#include <intrins.h>

//sbit SCK = P1^7;        
//sbit SDA = P2^3;        
//sbit RST = P1^3; 

//变量及函数声明


void Write_Ds1302(unsigned char temp);
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
unsigned char Read_Ds1302_Byte( unsigned char address );
void Set_Rtc(unsigned char* ucRtc);
void Read_Rtc(unsigned char* ucRtc);

#endif

工程主函数内容:

1.头文件声明(把需要用到的头文件添加进来)


/*头文件声明区*/
#include <STC15F2K60S2.H>//单片机寄存器专用头文件

#include <Init.h>//初始化底层驱动专用头文件
#include <Led.h>//Led底层驱动专用文件
#include <Key.h>//按键底层驱动专用文件
#include <Seg.h>//数码管底层驱动专用文件
#include "ds1302.h" //时钟专用头文件

2.变量声明(把需要用到的所有变量现在这里进行声明)


/*变量声明区*/
unsigned char Key_Val,Key_Down,Key_Old,Key_Up;//按键扫描专用变量
unsigned char Key_Slow_Down;//按键减速专用变量 10ms
unsigned char Seg_Buf[8] = {10,10,10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Point[8] = {0,0,0,0,0,0,0,0};//数码管小数点数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned char Seg_Slow_Down;//数码管减速专用变量 500ms
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};//Led显示数据存放数组
unsigned char ucRtc[3] = {0x23,0x59,0x55};//时钟数据存放数组,默认时间23:59:55

3.按键处理函数(在这里编写按键控制的函数)


/*键盘处理函数 */
void Key_Proc()//每10ms检查一下按键有没有被按下
{
        if(Key_Slow_Down)return;
        Key_Slow_Down = 1;//按键减速程序
        
        Key_Val = Key_Read();//读取按下的键码值
        Key_Down = Key_Val & (Key_Val ^ Key_Old);//捕捉下降沿
        Key_Up = ~Key_Val & (Key_Val ^ Key_Old);//捕捉上升沿
        Key_Old = Key_Val;//辅助扫描
}

4.信息处理函数(需要使用到到的函数进行简单的预处理)


/*信息处理函数*/
void Seg_Proc()
{
        //unsigned char i;//用于for循环
        if(Seg_Slow_Down)return;
        Seg_Slow_Down = 1;//数码管减速程序
    


    /*信息读取区域*/


    Read_Rtc(ucRtc);//实时读取时钟数据
    


    /*数据处理区域*/

//此处是控制数码管显示状态,使用BCD码的形式(时钟用BCD码的形式读取),需要把十进制更换16进制,向16求余和取整
    Seg_Buf[0] = ucRtc[0] / 16;
    Seg_Buf[1] = ucRtc[0] % 16;
    Seg_Buf[2] = 11;//11代表 -
    Seg_Buf[3] = ucRtc[1] / 16;
    Seg_Buf[4] = ucRtc[1] % 16;
    Seg_Buf[5] = 11;
    Seg_Buf[6] = ucRtc[2] / 16;
    Seg_Buf[7] = ucRtc[2] % 16;
//    for (i=0;i<3;i++)这个for循环和Seg_Buf[]的这几条语句效果一样,但是写法可以更简洁
//    {
//        Seg_Buf[3*i] = ucRtc[i] / 16;
//        Seg_Buf[3*i+1] = ucRtc[i] % 16;
//    }
//    Seg_Buf[2] = Seg_Buf[5] = 11;
    
}
    


5.其他函数(其他编写的函数,在这里书写会比较方便理解)


/*其他函数*/
void Led_Proc()
{
    
}

6.定时器0中断初始化函数

(这个可以使用STC的定时器计算那里生成c代码,后面要自己添加ET0,EA打开中断)
/*定时器0中断初始化函数*/
void Timer0Init(void)        //1毫秒@12.000MHz
{
    TMOD &= 0xF0;        //设置定时器模式
    TL0 = 0x18;        //设置定时初值
    TH0 = 0xFC;        //设置定时初值
    TF0 = 0;        //清除TF0标志
    TR0 = 1;        //定时器0开始计时
    
    ET0 = 1;
    EA = 1;
}


7.定时器0中断服务函数


(为了定时执行特定的任务,如此处设置了定时的时间触发了数码管和LED产生特定反应)
/*定时器0中断服务函数*/ //定时中断函数每1ms进行一次中断处理
void Timer0Server() interrupt 1
{
    
        if(++Key_Slow_Down == 10)Key_Slow_Down =0;
        if(++Seg_Slow_Down == 500)Seg_Slow_Down =0;
        if(++Seg_Pos == 8)Seg_Pos = 0;
    
        Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);//每1ms运行一次显示函数显示内容
        Led_Disp(Seg_Pos,ucLed[Seg_Pos]);
}

8.主函数Main(调用书写的函数实现所需的相应功能)


/*Main*/

void main()
{
    System_Init();
    Timer0Init();
    Set_Rtc(ucRtc);//上电时设置时间
    while(1)
    {
        Key_Proc();
        Seg_Proc();
        Led_Proc();
        
    }

  • 30
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值