stm32+DS1302+TM1638驱动程序

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<>=1;
    for(i=0;i<8;i++){
        if(0x01<return i+1;
    }
    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)