TM1638数码管显示驱动程序(参考)
Vcc--电源+
GND--电源地
STB--PA0
CLK--PA1
DIO--PA2
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
用到的函数: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.
***********************************************************************************************/
Vcc--电源+
GND--电源地
CLK--PC12
DAT--PC11
RST--PC10
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);