stm32+DS1302+TM1638驱动程序

2018-06-25来源: eefocus关键字:stm32  DS1302  TM1638  驱动程序

1、TM1638与STM32连接


1.1 硬件连接


    Vcc--电源+

    GND--电源地

    STB--PA0

    CLK--PA1

    DIO--PA2


1.2 驱动程序


TM1638.c文件:


/**********************************************************************************************

**Program Assignment: Driver for TM1638 digital tube

**Author        : 

**Date              : 

**Description       : This is a driver for the board which is controled by thechip of tm1638. 

              The board has eight digital tubes which have eight segments and eight keys.

***********************************************************************************************/

                          //#include "stm32f10x.h" 

#include "TM1638.h"


/*********************define and global variables*********************************************/

#define STB GPIO_Pin_0                          //chip-select line

#define CLK GPIO_Pin_1                                      //clock line

#define DIO GPIO_Pin_2                                                                      //data line

#define Set(x) GPIO_SetBits(GPIOA,(x))              //Sets the selected data port bits

#define Reset(x) GPIO_ResetBits(GPIOA,(x))          //Resets the selected data port bits

#define Get(x) GPIO_ReadInputDataBit(GPIOA,(x))==SET        //Read the specified input port pin



uint16_t const tm_dat[2][14]={{'0','1','2','3','4','5',     //the char and its segment code 

            '6','7','8','9','.','-','_',' '},

            {0x3F,0x06,0x5B,0x4F,0x66,0x6D,

            0x7D,0x07,0x7F,0x6F,0x80,0x40,

            0x08,0x00}};


/***********************************************************************************************

*Function Name: RCC_Config      

*Purpose      : Configration Clock

***********************************************************************************************/

void RCC_Config(){

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

}


/***********************************************************************************************

*Function Name: GPIO_Config     

*Purpose      : Configration GPIO

***********************************************************************************************/

void GPIO_Config(){

    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;

    GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;

    GPIO_InitStructure.GPIO_Pin=STB|CLK|DIO;

    GPIO_Init(GPIOA,&GPIO_InitStructure);

}

/***********************************************************************************************

*Function Name: Write_Byte      

*Purpose      : Write one byte to the data port

*params       : byte  -------8-bits byte  

*return       : none

***********************************************************************************************/

void Write_Byte(uint8_t byte){

    uint8_t i=0;

    for(i=0;i<8;i++){

        Reset(CLK);

        if(byte&0x01){

            Set(DIO);

        }else{

            Reset(DIO);

        }

        Set(CLK);

        byte>>=1;

    }

}


/***********************************************************************************************

*Function Name: Read_Byte       

*Purpose      : Read one byte from data port

*params       : none

*return       : the 8-bits byte which is read from data port

***********************************************************************************************/

int8_t Read_Byte(){

    uint8_t i=0;

    uint8_t temp=0x00;

    for(i=0;i<8;i++){

        Set(CLK);

        temp>>=1;

        if(Get(DIO)){

            temp|=0x80;

        }

        Reset(CLK);

    }

    return temp;

}


/***********************************************************************************************

*Function Name: Write_Cmd       

*Purpose      : Write a conmand to the data port

*params       : cmd  -------8-bits byte,the conmand,check the data sheet to find the conmand 

*return       : none

***********************************************************************************************/

void Write_Cmd(uint8_t cmd){

    Set(STB);

    Reset(STB);

    Write_Byte(cmd);

}


/***********************************************************************************************

*Function Name: Read_Key        

*Purpose      : Read the key number which has been pressed

*params       : none

*return       : the number of the key. 0-8.  "return 0" represents no key has been pressed.

***********************************************************************************************/

int8_t Read_Key(){

    uint8_t i=0;

    uint8_t key1=0x00;

    uint16_t key2=0x00;

    Write_Cmd(0x42);

    Set(DIO);                       //this is obligatory, check the data sheet,GPIO

    for(i=0;i<4;i++){

        key1=Read_Byte();

        key2|=(key1<

    }

    key2>>=1;

    for(i=0;i<8;i++){

        if(0x01<

    }

    return 0;

}


/***********************************************************************************************

*Function Name: Write_Dat       

*Purpose      : Write data to the location specified

*params       : addr  ------the address,0x00 to 0x0f

        dat   ------the data,segment code

*return       : none

***********************************************************************************************/

void Write_Dat(uint8_t addr,uint8_t dat){

    Write_Cmd(0x44);

    Write_Cmd(0xc0|addr);

    Write_Byte(dat);

}


/***********************************************************************************************

*Function Name: TM1638_SendData     

*Purpose      : Write data to the location specified

*params       : i     ------the bit code of digtal tube,0 to 7

        str   ------the string,the char which was not in tm_data will be replace with "''".

*return       : none

***********************************************************************************************/

void TM1638_SendData(uint8_t i,char * str){

    int j=0,k=0;

    unsigned char chr;

    for(;i<8;i++){

        k=0;

        for(j=0;j<14;j++){

            if(*str==tm_dat[0][j]){

                chr=tm_dat[1][j];

                k=1;

                break;

            }

        }


        if(k==0){

            chr=0x00;

        }


        if(*(str+1)=='.'){

            chr|=0x80;

            Write_Dat(i*2,chr);

            str++;

        }else{

            Write_Dat(i*2,chr);

        }

        str++;

        if(*str=='\0')break;

    }

}


/***********************************************************************************************

*Function Name: TM1638_SendIntData      

*Purpose      : Write Int data to the location specified

*params       : i     ------the bit code of digtal tube,0 to 7

        num   ------the Int.

*return       : none

***********************************************************************************************/

void TM1638_SendIntData(uint8_t i,int num)

{

    char a;

    a = num + '0';

    TM1638_SendData(i,&a);

}


/***********************************************************************************************

*Function Name: TM1638_Init     

*Purpose      : the initialization of tm1638

*params       : none

*return       : none

***********************************************************************************************/

void TM1638_Init(){

    int i=0;

    RCC_Config();

    GPIO_Config();

    Write_Cmd(0x8a);

    Write_Cmd(0x40);

    for(i=0;i<16;i++){

        Write_Byte(0x00);

    }

}


TM1638.h


#ifndef __TM1638_H

#define __TM1638_H             

#include "stm32f10x.h"


void RCC_Config(void);

void GPIO_Config(void);

void Write_Byte(uint8_t byte);

int8_t Read_Byte(void);

void Write_Cmd(uint8_t cmd);

int8_t Read_Key(void);

void Write_Dat(uint8_t addr,uint8_t dat);

void TM1638_SendData(uint8_t i,char * str);

void TM1638_SendIntData(uint8_t i,int num);

void TM1638_Init(void);



#endif


1.3 函数说明


用到的函数:void TM1638_SendData(uint8_t i,char * str);函数说明如下:


/***********************************************************************************************

*Function Name: TM1638_SendData     

*Purpose      : Write data to the location specified

*params       : i     ------the bit code of digtal tube,0 to 7

        str   ------the string,the char which was not in tm_data will be replace with "''".不显示数据的时候用"''"替换字符

*return       : none

***********************************************************************************************/


int8_t Read_Key(void);函数说明如下:


/***********************************************************************************************

*Function Name: Read_Key        

*Purpose      : Read the key number which has been pressed

*params       : none

*return       : the number of the key. 0-8.  "return 0" represents no key has been pressed.

***********************************************************************************************/


2.DS1302与STM32


2.1硬件连接


   Vcc--电源+

   GND--电源地

   CLK--PC12

   DAT--PC11

   RST--PC10


2.2驱动程序


DS1302.c的程序网上很多都不能用,查找了硬件时序,发现没问题,但是就是没办法用,下面的程序我亲自测过可以用的,如下:


#include "DS1302.h"

//#include "IO.h"

#include "delay.h"  

//*****************DS1302控制命令*******************

#define WRITE_SECOND              0x80

#define WRITE_MINUTE              0x82

#define WRITE_HOUR                0x84

#define WRITE_DAY                 0x86

#define WRITE_MONTH               0x88

#define WRITE_WEEK                0x8A

#define WRITE_YEAR                0x8C

#define WRITE_TIMER_FLAG          0xC0


#define READ_SECOND               0x81

#define READ_MINUTE               0x83

#define READ_HOUR                 0x85

#define READ_DAY                  0x87

#define READ_MONTH                0x89

#define READ_WEEK                 0x8B

#define READ_YEAR                 0x8D

#define READ_TIMER_FLAG           0xC1

#define WRITE_PROTECT             0x8E

_calendar_obj calendar;                         //时钟结构体 

_next_obj next;                                     

//月份数据表                                          

u8 const table_week[12]={0,3,3,6,1,4,6,2,5,0,3,5}; //月修正数据表   

u8 BCD2HEX(u8 bcd_data)    //BCDtoHEX   

{   

    u8 temp;   

    temp=(bcd_data/16*10 + bcd_data%16);   

    return temp;   

}   

u8 HEX2BCD(u8 hex_data)    //HEXtoBCD    

{   

    u8 temp;   

    temp=(hex_data/10*16 + hex_data%10);   

    return temp;   

}   

//============================================

//函数名称:void Ds1302_Write_Byte (byte addr, byte dat)  

//功能:    串行发送地址、数据,先发低位,且在上升沿发送

//参数传递:有,地址和数据

//返回值:  无

//===========================================

 void IO_Init(void)

{   

    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC, ENABLE); //使能PA,PB,PC端口时钟

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;                                                            //IO口速度为50MHz   

    //PC端口初始化   

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12;                      //设置PC10~PC12端口推挽输出

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;                                                       //推挽输出  

    GPIO_Init(GPIOC, &GPIO_InitStructure);                                                                                          

}



void Ds1302_Write_Byte(u8 addr, u8 dat)     

{

    u8 i;

  DS1302_IO_OUT();                //数据端口定义为输出

  CE = 1;

    delay_us(10);

    SCLK = 0;

    delay_us(10);

    for(i=0;i<8;i++) 

    { 

        if(addr&0x01) 

        {

            DIO = 1;

        }

        else 

        {

            DIO = 0;

        }

        addr = addr>>1;

        SCLK = 1;

        delay_us(10);

        SCLK = 0;

        delay_us(10);


    } 

    for(i=0;i<8;i++)            //写入数据:dat

  {

        if(dat&0x01) 

        {

            DIO = 1;

        }

        else 

        {

            DIO = 0;

        }

        dat = dat>>1;

        SCLK = 1;

        delay_us(10);

        SCLK = 0;

        delay_us(10);

  }

  CE = 0;;                     //停止DS1302总线

    delay_us(10);

}

//===============================================

//函数名称:byte Ds1302_Read_Byte ( byte addr )

//功能:    串行读取数据,先发低位,且在下降沿发送

//参数传递:有,地址

//返回值:  有,读取的数据

//===============================================

u8 Ds1302_Read_Byte(u8 addr)

{

  u8  i;

  u8  temp = 1;

    CE = 1;

    delay_us(10);

  for(i=0;i<8;i++) 

  {      

    SCLK = 0;

        delay_us(10);

        if(addr&0x01) 

    {

       DIO = 1;

    }

    else 

    {

       DIO = 0;

    }

        addr = addr>>1;

        SCLK = 1;

        delay_us(10);

  }

  DS1302_IO_IN();                  //数据端口定义为输入

  for(i=0;i<8;i++) 

  {

    temp = temp >> 1;                            //输出数据:temp

    SCLK = 0;

        delay_us(10);

        if(DIO_IN) 

    {

       temp |= 0x80;

    }

        SCLK = 1;

        delay_us(10);

  }

  DS1302_IO_OUT();                //数据端口定义为输出                       

  SCLK = 0;

    delay_us(10);

    CE = 0;                         //停止DS1302总线

    delay_us(10);

    return temp;                    

}

//获得现在是星期几

//功能描述:输入公历日期得到星期(只允许1901-2099年)

//输入参数:公历年月日 

//返回值:星期号                                                                                        

u8 RTC_Get_Week(u16 year,u8 month,u8 day)

{   

    u16 temp2;

    u8 yearH,yearL; 

    yearH=year/100; 

    yearL=year%100;                                     //如果为21世纪,年份数加100  

    if (yearH>19)yearL+=100;                    //所过闰年数只算1900年之后的  

    temp2=yearL+yearL/4;

    temp2=temp2%7; 

    temp2=temp2+day+table_week[month-1];

    if (yearL%4==0&&month<3)temp2--;

    return(temp2%7);

}             

//===============================================

//           向DS1302写入时钟数据

//===============================================

void RTC_Set(u16 year,u8 mon,u8 day,u8 hour,u8 min,u8 sec) 

{    

    u8 WR_week;

    u8 WR_yearL = 0;

    if(year>=2000)

    {

        WR_yearL = year - 2000;

    }

    WR_week = RTC_Get_Week(year,mon,day);                        //根据写入的日期算星期几

    Ds1302_Write_Byte(WRITE_PROTECT,0x00);           //关闭写保护 

    Ds1302_Write_Byte(WRITE_SECOND,0x80);            //暂停 

//  Ds1302_Write_Byte(ds1302_charger_add,0xa9);    //涓流充电 

    Ds1302_Write_Byte(WRITE_YEAR,HEX2BCD(WR_yearL)); //年 

    Ds1302_Write_Byte(WRITE_MONTH,HEX2BCD(mon));     //月 

    Ds1302_Write_Byte(WRITE_DAY,HEX2BCD(day));       //日 

    Ds1302_Write_Byte(WRITE_HOUR,HEX2BCD(hour));     //时 

    Ds1302_Write_Byte(WRITE_MINUTE,HEX2BCD(min));    //分

    Ds1302_Write_Byte(WRITE_SECOND,HEX2BCD(sec));    //秒

    Ds1302_Write_Byte(WRITE_WEEK,HEX2BCD(WR_week));  //周 

    Ds1302_Write_Byte(WRITE_PROTECT,0x80);           //打开写保护 

}


//========================================

//           从DS1302读出时钟数据

//========================================

void GetTime(void)  

//  u8  i,tmp;

    calendar.w_year  = BCD2HEX(Ds1302_Read_Byte(READ_YEAR));                    //年 

    calendar.w_month = BCD2HEX(Ds1302_Read_Byte(READ_MONTH));         //月 

    calendar.w_date  = BCD2HEX(Ds1302_Read_Byte(READ_DAY));           //日 

    calendar.hour    = BCD2HEX(Ds1302_Read_Byte(READ_HOUR));          //时 

    calendar.min     = BCD2HEX(Ds1302_Read_Byte(READ_MINUTE));        //分 

    calendar.sec     = BCD2HEX(Ds1302_Read_Byte(READ_SECOND)&0x7F);     //秒 

    calendar.week    = BCD2HEX(Ds1302_Read_Byte(READ_WEEK));          //周 

    calendar.w_year  = calendar.w_year+2000;

}





//==========================================

//              DS1302初始化

//==========================================

void Ds1302_Init(void)

    IO_Init();

  CE = 0;                                           //RST脚置低

  SCLK = 0;                                         //SCK脚置低

    Ds1302_Write_Byte(WRITE_SECOND,0x00);           //开始  

  //RTC_Set(2017,4,18,15,23,2) ;

}

//*******************以下UTC时间计算部分函数*****************

//判断是否是闰年函数

//月份   1  2  3  4  5  6  7  8  9  10 11 12

//闰年   31 29 31 30 31 30 31 31 30 31 30 31

//非闰年 31 28 31 30 31 30 31 31 30 31 30 31

//输入:年份

//输出:该年份是不是闰年.1,是.0,不是

u8 Is_Leap_Year(u16 year)

{             

    if(year%4==0)                                                               //必须能被4整除

    { 

        if(year%100==0) 

        { 

            if(year%400==0)return 1;                                    //如果以00结尾,还要能被400整除        

            else return 0;   

        }else return 1;   

    }else return 0; 

}                  


DS1302.h内容如下:


#ifndef __DS1302_H

#define __DS1302_H

#include "sys.h"

#endif



//-------------------------------------------------------------------------*

//文件名:  DS1302.h (实时时钟头文件)                                          *

//-------------------------------------------------------------------------*

//IO方向设置


#define CE                  PCout(10)           // PC10

#define DIO                 PCout(11)           // PC11

#define SCLK                PCout(12)           // PC12


#define DS1302_IO_IN()  {GPIOC->CRH&=0xFFFF0FFF;GPIOC->CRH|=0x00008000;}                //低八位引脚的PC11脚定义为输入

#define DS1302_IO_OUT() {GPIOC->CRH&=0xFFFF0FFF;GPIOC->CRH|=0x00003000;}        //低八位引脚的PC11脚定义为输出

//IO操作函数                                               

#define DIO_OUT PCout(11)           //数据端口  PC11

#define DIO_IN  PCin(11)            //数据端口  PC11

typedef struct 

{

    u8  sec;

    u8  min;

    u8  hour;

    u8  day;

    u8  mon;

  u16 year;

    u8  week;

}_next_obj; 

extern _next_obj next;

typedef struct 

{

    vu8 hour;

    vu8 min;

    vu8 sec;            

    //公历日月年周

    vu16 w_year;

    vu8  w_month;

    vu8  w_date;

    vu8  week;       

}_calendar_obj; 

extern _calendar_obj calendar;  //日历结构体


extern u32 RTC_sec_sum;                                                     //当前时间的总秒值

extern u32 Program_sec_sum;                                             //当前编程任务的总秒值,与RTC_sec_sum进行比较

void RTC_Set(u16 year,u8 mon,u8 day,u8 hour,u8 min,u8 sec);

void GetTime(void);

void NEXT_Date(u8 day);

u8 RTC_Pro_count(u16 syear,u8 smon,u8 sday,u8 hour,u8 min,u8 sec,u8 mode);//编程任务时间计算

u8 Pro_Get_time(u32 ttt);                               //编程模式无效时间时计算下次开始的日期

void Ds1302_Init(void);


关键字:stm32  DS1302  TM1638  驱动程序 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/article_2018062539989.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:STM32与DS1302的接口电路
下一篇:关于STM32驱动DS1302实时时钟的一点思考

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

STM32-modbus rtu 之从机程序
STM32-modbus rtu 之从机程序以前移植过freemodbus,这次是自己重新写,只实现保持寄存器的读写。一、串口这部分跟上一篇文章主机程序一样,DMA接收,直接发送。二、错误反馈/*发送 错误反馈*/void  mb_sentACK( u8 cm,u8 err){    u16 temp;    serialTXbuf_st.buf[0] = local_addr;    serialTXbuf_st.buf[1] = cm+0x80;    serialTXbuf_st.buf[2] =  err; 
发表于 2019-12-02
STM32-modbus rtu 之从机程序
STM32 堆栈的理解
1、MDK STM32的内存分配 (摘自网络)C语言上分为栈、堆、bss、data、code段。具体每个段具体是存储什么数据的,直接百度吧。重点分析一下STM32以及在MDK里面段的划分。MDK下Code,RO-data,RW-data,ZI-data这几个段:Code是存储程序代码的。RO-data是存储const常量和指令。RW-data是存储初始化值不为0的全局变量。ZI-data是存储未初始化的全局变量或初始化值为0的全局变量。Flash=Code + RO Data + RW Data;RAM= RW-data+ZI-data;这个是MDK编译之后能够得到的每个段的大小,也就能得到占用相应的FLASH和RAM的大小
发表于 2019-12-02
STM32 堆栈的理解
STM32堆栈空间大小设置
1. 设置堆栈空间大小在使用STM32编程时,一般情况下我们不会关注堆栈空间的大小,因为在STM32的启动文件中,已经帮我们预先设置好了堆栈空间的大小。如下图所示的启动代码中,Stack栈的大小为:0x400(1024Byte),Heap堆的大小为:0x200(512Byte)。这也是为什么一个基础的工程编译后,RAM的空间也占用了1.6K左右的原因,因为堆栈的空间均分配在RAM中,可在编译的map文件中查看RAM资源占用的情况。若工程中使用的局部变量较多,定义的数据长度较大时,若不调整栈的空间大小,则会导致程序出现栈溢出,程序运行结果与预期的不符或程序跑飞。这时我们就需要手动的调整栈的大小。当工程中使用了malloc动态分配
发表于 2019-12-02
STM32堆栈空间大小设置
STM32--堆栈空间
函数的局部变量,都是存放在"栈"里面,栈的英文是:STACK.STACK的大小,可以在STM32的启动文件里面设置,以战舰开发板为例,在startup_stm32f10x_hd.s里面:Stack_Size      EQU     0x00000400                  AREA    STACK, NOINIT, READWRITE, ALIGN=3Stack_Mem       SPACE  
发表于 2019-12-02
STM32的堆栈(Heap&Stack)空间
最近做的一个项目遇到一个很莫名的错误,程序运行到某一部分时便会卡死,分析后,感觉在逻辑上并无错误,但是就是会卡死,而且不是偶然。 后来在网上查找资料怀疑是内存溢出,然后调试发现是两个函数中的的局部变量申请的内存空间太大,所以错误应该是栈溢出了。将这两个变量使用malloc申请堆段空间完美解决。下面是对STM32的堆栈(Heap&Stack)小结:内存分配空间 内核保护区栈段堆段数据区代码区代码区 :静态区 常量(const) 函数代码逻辑数据区:静态区 全局变量 局部变量+static堆段:动态区,管理者是程序员 malloc申请的空间栈段:动态区,管理
发表于 2019-12-02
STM32的堆栈(Heap&Stack)空间
stm8s 定时器2测量脉冲宽度(单位 us)
void Init_Timer2(void){  GPIO_Init(GPIOA, GPIO_PIN_3, GPIO_MODE_IN_PU_NO_IT);//输入 无中断  TIM2_TimeBaseInit(TIM2_PRESCALER_16,65536-1);       //16分频, 65ms 溢出  TIM2_Cmd(ENABLE);  }uint16_t TIM2_GetCapture(void){  /* Get the Capture  Register value */  uint16_t tmpccr = 0;&n
发表于 2019-12-02
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved