用stm32控制并读取DS1302,外加TFT屏幕显示实时时间
一:DS1302
1.概述:
DS1302 是 DALLAS 公司推出的涓流充电时钟芯片,内含有一个实时时钟/日历和 31 字节静态RAM 通过简单的串行接口与单片机进行通信。
实时时钟/日历电路提供秒 、分 、时 、日 、日期 、月 、年的信息,而且每月的天 数和闰年的天数可自动调整。
时钟操作可通过 AM/PM 指示决定采用 24 或 12 小时格式 DS1302 与单片机之
间能简单地采用同步串行的方式进行通信,
通信仅需用到三个口线: RES(复位 )、I/O (数据线 )、SCLK(串行时钟 )。
时钟/RAM 的读/写数据以一个字节或多达 31 个字节的字符组方式通信 DS1302 工作时功耗很
低,保持数据和时钟信息时功率小于 1mW 。
该模块采用双电源供电,当模块连接单片机主板时,由单片机的主电源供电,否则采用备用电源,一般是一个纽扣电池,有助于模块与主电源断开连接时,DS1302芯片内部任然可以进行走时操作。
2.管脚描述:
X1 X2 ——32.768KHz 晶振管脚
GND ——地
RST ——复位脚
I/O ——数据输入/输出引脚
SCLK ——串行时钟
Vcc1,Vcc2 ——电源供电管脚
二:TFT
1.概述:
QD180AR7735模块是1.8“TFTLCD,65K彩色128×160分辨率。该LCD模块的控制器为ST7735,支持4线SPI控制接口。此外,该模块还包括5V-3.3V电源转换电路和IO-电平转换电路,它还包括SD卡插座。
(我使用的就是8针1.8寸的TFT屏幕)
2.管脚描述
1 | VCC | 电源输入(3.3V/5V) |
2 | GND | 接地 |
3 | CS | 液晶屏片选信号,低电平使能 |
4 | RESET | 液晶屏复位信号,低电平复位 |
5 | A0 | 液晶屏寄存器/数据选择信号,高电平:寄存器,低电平:数据 |
6 | SDA | SPI总线写数据信号 |
7 | SCK | SPI总线时钟信号 |
8 | LED | 背光控制,高电平点亮,如无需控制则接3.3V常亮 |
三.代码实现:
DS1302.c文件:
#include "ds1302.h"
#include "delay.h"
struct TIMEData TimeData;
char read_time[7];
char DS1302_data_1[10];
char DS1302_data_2[8];
void ds1302_gpio_init()//CE,SCLK端口初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //PC.11 CE
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.11
GPIO_ResetBits(GPIOC,GPIO_Pin_0);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //PC.12 SCLK
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.12
GPIO_ResetBits(GPIOC,GPIO_Pin_3);
}
void ds1302_DATAOUT_init()//配置双向I/O端口为输出态
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PC.10 DATA
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.10
GPIO_ResetBits(GPIOC,GPIO_Pin_2);
}
void ds1302_DATAINPUT_init()//配置双向I/O端口为输入态
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PC.10 DATA
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC.10
}
void ds1302_write_onebyte(unsigned char data)//向DS1302发送一字节数据
{
unsigned char count=0;
ds1302_DATAOUT_init();
SCLK_L;
for(count=0;count<8;count++)
{ SCLK_L;
if(data&0x01)
{DATA_H;}
else{DATA_L;}//先准备好数据再发送
SCLK_H;//拉高时钟线,发送数据
data>>=1;
}
}
void ds1302_wirte_rig(unsigned char address,unsigned char data)//向指定寄存器地址发送数据
{
unsigned char temp1=address;
unsigned char temp2=data;
CE_L;SCLK_L;delay_us(1);
CE_H;delay_us(2);
ds1302_write_onebyte(temp1);
ds1302_write_onebyte(temp2);
CE_L;SCLK_L;delay_us(2);
}
unsigned char ds1302_read_rig(unsigned char address)//从指定地址读取一字节数据
{
unsigned char temp3=address;
unsigned char count=0;
unsigned char return_data=0x00;
CE_L;SCLK_L;delay_us(3);
CE_H;delay_us(3);
ds1302_write_onebyte(temp3);
ds1302_DATAINPUT_init();//配置I/O口为输入
delay_us(2);
for(count=0;count<8;count++)
{
delay_us(2);//使电平持续一段时间
return_data>>=1;
SCLK_H;delay_us(4);//使高电平持续一段时间
SCLK_L;delay_us(14);//延时14us后再去读取电压,更加准确
if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_2))
{return_data=return_data|0x80;}
}
delay_us(2);
CE_L;DATA_L;
return return_data;
}
void ds1302_init()
{
ds1302_wirte_rig(0x8e,0x00);//关闭写保护
ds1302_wirte_rig(0x80,0x00);//seconds 0秒
ds1302_wirte_rig(0x82,0x03);//minutes 03分
ds1302_wirte_rig(0x84,0x21);//hours 21时
ds1302_wirte_rig(0x86,0x19);//date 19日
ds1302_wirte_rig(0x88,0x01);//months 1月
ds1302_wirte_rig(0x8a,0x07);//days 星期日
ds1302_wirte_rig(0x8c,0x22);//year 2022年
ds1302_wirte_rig(0x8e,0x80);//关闭写保护
}
void ds1302_read_time()
{
read_time[0]=ds1302_read_rig(0x81);//读秒
read_time[1]=ds1302_read_rig(0x83);//读分
read_time[2]=ds1302_read_rig(0x85);//读时
read_time[3]=ds1302_read_rig(0x87);//读日
read_time[4]=ds1302_read_rig(0x89);//读月
read_time[5]=ds1302_read_rig(0x8B);//读星期
read_time[6]=ds1302_read_rig(0x8D);//读年
}
void ds1302_read_realTime()
{
ds1302_read_time(); //BCD码转换为10进制
TimeData.second=(read_time[0]>>4)*10+(read_time[0]&0x0f);
TimeData.minute=((read_time[1]>>4)&(0x07))*10+(read_time[1]&0x0f);
TimeData.hour=(read_time[2]>>4)*10+(read_time[2]&0x0f);
TimeData.day=(read_time[3]>>4)*10+(read_time[3]&0x0f);
TimeData.month=(read_time[4]>>4)*10+(read_time[4]&0x0f);
TimeData.week=read_time[5];
TimeData.year=(read_time[6]>>4)*10+(read_time[6]&0x0f)+2000;
DS1302_data_1[0]='2';
DS1302_data_1[1]='0';
DS1302_data_1[2]='0'+(TimeData.year-2000)/10;
DS1302_data_1[3]='0'+(TimeData.year-2000)%10;
DS1302_data_1[4]='-';
DS1302_data_1[5]='0'+TimeData.month/10;
DS1302_data_1[6]='0'+TimeData.month%10;
DS1302_data_1[7]='-';
DS1302_data_1[8]='0'+TimeData.day/10;
DS1302_data_1[9]='0'+TimeData.day%10;
DS1302_data_2[0]='0'+TimeData.hour/10;
DS1302_data_2[1]='0'+TimeData.hour%10;
DS1302_data_2[2]=':';
DS1302_data_2[3]='0'+TimeData.minute/10;
DS1302_data_2[4]='0'+TimeData.minute%10;
DS1302_data_2[5]=':';
DS1302_data_2[6]='0'+TimeData.second/10;
DS1302_data_2[7]='0'+TimeData.second%10;
}
DS1302.h文件:
#ifndef __ds1302_H
#define __ds1302_H
#define CE_L GPIO_ResetBits(GPIOC,GPIO_Pin_0)//拉低使能位
#define CE_H GPIO_SetBits(GPIOC,GPIO_Pin_0)//拉高使能位
#define SCLK_L GPIO_ResetBits(GPIOC,GPIO_Pin_3)//拉低时钟线
#define SCLK_H GPIO_SetBits(GPIOC,GPIO_Pin_3)//拉高时钟线
#define DATA_L GPIO_ResetBits(GPIOC,GPIO_Pin_2)//拉低数据线
#define DATA_H GPIO_SetBits(GPIOC,GPIO_Pin_2)//拉高数据线
struct TIMEData
{
unsigned int year;
unsigned char month;
unsigned char day;
unsigned char hour;
unsigned char minute;
unsigned char second;
unsigned char week;
};//创建TIMEData结构体方便存储时间日期数据
extern struct TIMEData TimeData;//全局变量
void ds1302_gpio_init(void);//ds1302端口初始化
void ds1302_write_onebyte(unsigned char data);//向ds1302发送一字节数据
void ds1302_wirte_rig(unsigned char address,unsigned char data);//向指定寄存器写一字节数据
unsigned char ds1302_read_rig(unsigned char address);//从指定寄存器读一字节数据
void ds1302_init(void);//ds1302初始化函数
void ds1302_DATAOUT_init(void);//IO端口配置为输出
void ds1302_DATAINPUT_init(void);//IO端口配置为输入
void ds1302_read_time(void);//从ds1302读取实时时间(BCD码)
void ds1302_read_realTime(void);//将BCD码转化为十进制数据
#endif
Lcd_Driver.c文件:
#include "stm32f10x.h"
#include "Lcd_Driver.h"
#include "LCD_Config.h"
#include "delay.h"
//本测试程序使用的是模拟SPI接口驱动
//可自由更改接口IO配置,使用任意最少4 IO即可完成本款液晶驱动显示
/******************************************************************************
接口定义在Lcd_Driver.h内定义,请根据接线修改并修改相应IO初始化LCD_GPIO_Init()
#define LCD_CTRL GPIOB //定义TFT数据端口
#define LCD_LED GPIO_Pin_9 //PB9--->>TFT --BL
#define LCD_RS (AO) GPIO_Pin_10 //PB10--->>TFT --RS/DC
#define LCD_CS GPIO_Pin_11 //PB11--->>TFT --CS/CE
#define LCD_RST GPIO_Pin_12 //PB12--->>TFT --RST
#define LCD_SCL GPIO_Pin_13 //PB13--->>TFT --SCL/SCK
#define LCD_SDA GPIO_Pin_15 //PB15 MOSI--->>TFT --SDA/DIN
*******************************************************************************/
//液晶IO初始化配置
void LCD_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB ,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9| GPIO_Pin_10| GPIO_Pin_11| GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/****************************************************************************
* 名 称:void ili9320_WriteIndex(u16 idx)
* 功 能:写 ili9320 控制器寄存器地址
* 入口参数:idx 寄存器地址
* 出口参数:无
* 说 明:调用前需先选中控制器,内部函数
* 调用方法:ili9320_WriteIndex(0x0000);
****************************************************************************/
void Lcd_WriteIndex(u8 Index)
{
u8 i=0;
//SPI 写命令时序开始
LCD_CS_CLR;
LCD_RS_CLR;
//刷屏100次 32秒 320ms/屏
for(i=8;i>0;i--)
{
if(Index&0x80)
LCD_SDA_SET; //输出数据
else
LCD_SDA_CLR;
LCD_SCL_CLR;
LCD_SCL_SET;
Index<<=1;
}
LCD_CS_SET;
}
/****************************************************************************
* 名 称:void ili9320_WriteData(u16 dat)
* 功 能:写 ili9320 寄存器数据
* 入口参数:dat 寄存器数据
* 出口参数:无
* 说 明:向控制器指定地址写入数据,调用前需先写寄存器地址,内部函数
* 调用方法:ili9320_WriteData(0x1030)
****************************************************************************/
void Lcd_WriteData(u8 Data)
{
u8 i=0;
LCD_CS_CLR;
LCD_RS_SET;
//刷屏100次 32秒 320ms/屏
for(i=8;i>0;i--)
{
if(Data&0x80)
LCD_SDA_SET; //输出数据
else LCD_SDA_CLR;
LCD_SCL_CLR;
LCD_SCL_SET;
Data<<=1;
}
LCD_CS_SET;
}
void Lcd_WriteReg(u8 Index,u8 Data)
{
Lcd_WriteIndex(Index);
Lcd_WriteData(Data);
}
void Lcd_Reset(void)
{
LCD_RST_CLR;
delay_ms(100);
LCD_RST_SET;
delay_ms(50);
}
void Lcd_Init(u8 dir)
{
LCD_GPIO_Init();
Lcd_Reset();
if(dir==0)//Init for ST7735R
{
Lcd_WriteIndex(0x11);//Sleep exit
delay_ms (120);
//ST7735R Frame Rate
Lcd_WriteIndex(0xB1);
Lcd_WriteData(0x01); Lcd_WriteData(0x2C); Lcd_WriteData(0x2D);
Lcd_WriteIndex(0xB2);
Lcd_WriteData(0x01); Lcd_WriteData(0x2C); Lcd_WriteData(0x2D);
Lcd_WriteIndex(0xB3);
Lcd_WriteData(0x01); Lcd_WriteData(0x2C); Lcd_WriteData(0x2D);
Lcd_WriteData(0x01); Lcd_WriteData(0x2C); Lcd_WriteData(0x2D);
Lcd_WriteIndex(0xB4); //Column inversion
Lcd_WriteData(0x07);
//ST7735R Power Sequence
Lcd_WriteIndex(0xC0);
Lcd_WriteData(0xA2); Lcd_WriteData(0x02); Lcd_WriteData(0x84);
Lcd_WriteIndex(0xC1); Lcd_WriteData(0xC5);
Lcd_WriteIndex(0xC2);
Lcd_WriteData(0x0A); Lcd_WriteData(0x00);
Lcd_WriteIndex(0xC3);
Lcd_WriteData(0x8A); Lcd_WriteData(0x2A);
Lcd_WriteIndex(0xC4);
Lcd_WriteData(0x8A); Lcd_WriteData(0xEE);
Lcd_WriteIndex(0xC5); //VCOM
Lcd_WriteData(0x0E);
Lcd_WriteIndex(0x36); //MX, MY, RGB mode
Lcd_WriteData(0xC0);
//ST7735R Gamma Sequence
Lcd_WriteIndex(0xe0);
Lcd_WriteData(0x0f); Lcd_WriteData(0x1a);
Lcd_WriteData(0x0f); Lcd_WriteData(0x18);
Lcd_WriteData(0x2f); Lcd_WriteData(0x28);
Lcd_WriteData(0x20); Lcd_WriteData(0x22);
Lcd_WriteData(0x1f); Lcd_WriteData(0x1b);
Lcd_WriteData(0x23); Lcd_WriteData(0x37); Lcd_WriteData(0x00);
Lcd_WriteData(0x07);
Lcd_WriteData(0x02); Lcd_WriteData(0x10);
Lcd_WriteIndex(0xe1);
Lcd_WriteData(0x0f); Lcd_WriteData(0x1b);
Lcd_WriteData(0x0f); Lcd_WriteData(0x17);
Lcd_WriteData(0x33); Lcd_WriteData(0x2c);
Lcd_WriteData(0x29); Lcd_WriteData(0x2e);
Lcd_WriteData(0x30); Lcd_WriteData(0x30);
Lcd_WriteData(0x39); Lcd_WriteData(0x3f);
Lcd_WriteData(0x00); Lcd_WriteData(0x07);
Lcd_WriteData(0x03); Lcd_WriteData(0x10);
Lcd_WriteIndex(0x2a);
Lcd_WriteData(0x00);Lcd_WriteData(0x00);
Lcd_WriteData(0x00);Lcd_WriteData(0x7f);
Lcd_WriteIndex(0x2b);
Lcd_WriteData(0x00);Lcd_WriteData(0x00);
Lcd_WriteData(0x00);Lcd_WriteData(0x9f);
Lcd_WriteIndex(0xF0); //Enable test command
Lcd_WriteData(0x01);
Lcd_WriteIndex(0xF6); //Disable ram power save mode
Lcd_WriteData(0x00);
Lcd_WriteIndex(0x3A); //65k mode
Lcd_WriteData(0x05);
Lcd_WriteIndex(0x29);//Display on
}
else if(dir==1) //Init for ST7735S
{
Lcd_WriteIndex(0x11);
delay_ms (120); //Delay 120ms
Lcd_WriteIndex(0xb1);
Lcd_WriteData(0x05);
Lcd_WriteData(0x3c);
Lcd_WriteData(0x3c);
Lcd_WriteIndex(0xb2);
Lcd_WriteData(0x05);
Lcd_WriteData(0x3c);
Lcd_WriteData(0x3c);
Lcd_WriteIndex(0xb3);
Lcd_WriteData(0x05);
Lcd_WriteData(0x3c);
Lcd_WriteData(0x3c);
Lcd_WriteData(0x05);
Lcd_WriteData(0x3c);
Lcd_WriteData(0x3c);
Lcd_WriteIndex(0xb4);
Lcd_WriteData(0x03);
Lcd_WriteIndex(0xc0);
Lcd_WriteData(0x2e);
Lcd_WriteData(0x06);
Lcd_WriteData(0x04);
Lcd_WriteIndex(0xc1);
Lcd_WriteData(0xc0);
Lcd_WriteIndex(0xc2);
Lcd_WriteData(0x0d);
Lcd_WriteData(0x00);
Lcd_WriteIndex(0xc3);
Lcd_WriteData(0x8d);
Lcd_WriteData(0xea);
Lcd_WriteIndex(0xc5);//set vcom
Lcd_WriteData(0x03);//VCOM=
Lcd_WriteIndex(0xc4);
Lcd_WriteData(0x8d);
Lcd_WriteData(0xee);
//Lcd_WriteIndex(0x21);
Lcd_WriteIndex(0x36);
Lcd_WriteData(0xc0);
Lcd_WriteIndex(0xe0);
Lcd_WriteData(0x03);
Lcd_WriteData(0x1f);
Lcd_WriteData(0x06);
Lcd_WriteData(0x0b);
Lcd_WriteData(0x35);
Lcd_WriteData(0x35);
Lcd_WriteData(0x30);
Lcd_WriteData(0x33);
Lcd_WriteData(0x31);
Lcd_WriteData(0x2e);
Lcd_WriteData(0x34);
Lcd_WriteData(0x3e);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x01);
Lcd_WriteData(0x03);
Lcd_WriteIndex(0xe1);
Lcd_WriteData(0x03);
Lcd_WriteData(0x1e);
Lcd_WriteData(0x06);
Lcd_WriteData(0x0b);
Lcd_WriteData(0x35);
Lcd_WriteData(0x34);
Lcd_WriteData(0x2f);
Lcd_WriteData(0x33);
Lcd_WriteData(0x32);
Lcd_WriteData(0x2e);
Lcd_WriteData(0x35);
Lcd_WriteData(0x3e);
Lcd_WriteData(0x00);
Lcd_WriteData(0x01);
Lcd_WriteData(0x02);
Lcd_WriteData(0x04);
Lcd_WriteIndex(0x21);
Lcd_WriteIndex(0x29);
Lcd_WriteIndex(0x2c);
}
else if(dir==2)//Init for ILI9163
{
Lcd_WriteIndex(0x11); //start OSC
delay_ms (100);
Lcd_WriteIndex(0x3a); //start OSC
Lcd_WriteData(0x05);
Lcd_WriteIndex(0x26); //start OSC
Lcd_WriteData(0x04);
Lcd_WriteIndex(0xf2); //Driver Output Control(1)
Lcd_WriteData(0x01);
Lcd_WriteIndex(0xe0); //Driver Output Control(1)
Lcd_WriteData(0x3f);
Lcd_WriteData(0x25);
Lcd_WriteData(0x1c);
Lcd_WriteData(0x1e);
Lcd_WriteData(0x20);
Lcd_WriteData(0x12);
Lcd_WriteData(0x2a);
Lcd_WriteData(0x90);
Lcd_WriteData(0x24);
Lcd_WriteData(0x11);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteIndex(0xe1); //Driver Output Control(1)
Lcd_WriteData(0x20);
Lcd_WriteData(0x20);
Lcd_WriteData(0x20);
Lcd_WriteData(0x20);
Lcd_WriteData(0x05);
Lcd_WriteData(0x00);
Lcd_WriteData(0x15);
Lcd_WriteData(0xa7);
Lcd_WriteData(0x3d);
Lcd_WriteData(0x18);
Lcd_WriteData(0x25);
Lcd_WriteData(0x2a);
Lcd_WriteData(0x2b);
Lcd_WriteData(0x2b);
Lcd_WriteData(0x3a);
Lcd_WriteIndex(0xb1); //LCD Driveing control
Lcd_WriteData(0x08);
Lcd_WriteData(0x08);
Lcd_WriteIndex(0xb4); //LCD Driveing control
Lcd_WriteData(0x07);
Lcd_WriteIndex(0xc0); //LCD Driveing control
Lcd_WriteData(0x0a);
Lcd_WriteData(0x02);
Lcd_WriteIndex(0xc1); //LCD Driveing control
Lcd_WriteData(0x02);
Lcd_WriteIndex(0xc5); //LCD Driveing control
Lcd_WriteData(0x4f);
Lcd_WriteData(0x5a);
Lcd_WriteIndex(0xc7); //LCD Driveing control
Lcd_WriteData(0x40);
Lcd_WriteIndex(0x2a); //LCD Driveing control
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x7f);
Lcd_WriteIndex(0x2b); //LCD Driveing control
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x00);
Lcd_WriteData(0x7f);
Lcd_WriteIndex(0x36); //LCD Driveing control
Lcd_WriteData(0xc8);//横屏0xA8 竖屏0xC8
Lcd_WriteIndex(0xb7); //LCD Driveing control
Lcd_WriteData(0x00);
// Lcd_WriteIndex(0xb8); //LCD Driveing control
// Lcd_WriteData(0x01);
Lcd_WriteIndex(0x29);
Lcd_WriteIndex(0x2c);
}
}
/*************************************************
函数名:LCD_Set_Region
功能:设置lcd显示区域,在此区域写点数据自动换行
入口参数:xy起点和终点,Y_IncMode表示先自增y再自增x
返回值:无
*************************************************/
void Lcd_SetRegion(u16 x_start,u16 y_start,u16 x_end,u16 y_end)
{
Lcd_WriteIndex(0x2a);
Lcd_WriteData(0x00);
Lcd_WriteData(x_start);
Lcd_WriteData(0x00);
Lcd_WriteData(x_end);
Lcd_WriteIndex(0x2b);
Lcd_WriteData(0x00);
Lcd_WriteData(y_start);
Lcd_WriteData(0x00);
Lcd_WriteData(y_end);
Lcd_WriteIndex(0x2c);
}
/*************************************************
函数名:LCD_Set_XY
功能:设置lcd显示起始点
入口参数:xy坐标
返回值:无
*************************************************/
void Lcd_SetXY(u16 x,u16 y)
{
Lcd_SetRegion(x,y,x,y);
}
/*************************************************
函数名:LCD_DrawPoint
功能:画一个点
入口参数:无
返回值:无
*************************************************/
void Gui_DrawPoint(u16 x,u16 y,u16 Data)
{
Lcd_SetRegion(x,y,x+1,y+1);
Lcd_WriteData(Data>>8);
Lcd_WriteData(Data);
}
/*****************************************
函数功能:读TFT某一点的颜色
出口参数:color 点颜色值
******************************************/
unsigned int Lcd_ReadPoint(u16 x,u16 y)
{
unsigned int Data;
Lcd_SetXY(x,y);
//Lcd_ReadData();//丢掉无用字节
//Data=Lcd_ReadData();
Lcd_WriteData(Data);
return Data;
}
/*************************************************
函数名:Lcd_Clear
功能:全屏清屏函数
入口参数:填充颜色COLOR
返回值:无
*************************************************/
void Lcd_Clear(u16 Color)
{
unsigned int i,m;
Lcd_SetRegion(0,0,X_MAX_PIXEL-1,Y_MAX_PIXEL-1);
Lcd_WriteIndex(0x2C);
for(i=0;i<128;i++)
for(m=0;m<160;m++)
{
Lcd_WriteData(Color>>8);
Lcd_WriteData(Color);
}
}
Lcd_Driver.h文件:
#define RED 0xf800
#define GREEN 0x07e0
#define BLUE 0x001f
#define WHITE 0xffff
#define BLACK 0x0000
#define YELLOW 0xFFE0
#define GRAY0 0xEF7D //灰色0 3165 00110 001011 00101
#define GRAY1 0x8410 //灰色1 00000 000000 00000
#define GRAY2 0x4208 //灰色2 1111111111011111
#define LCD_CTRL GPIOB //定义TFT数据端口
#define LCD_LED GPIO_Pin_9 //MCU_PB9--->>TFT --BL
#define LCD_RS GPIO_Pin_10 //PB11--->>TFT --RS/DC
#define LCD_CS GPIO_Pin_11 //MCU_PB11--->>TFT --CS/CE
#define LCD_RST GPIO_Pin_12 //PB10--->>TFT --RST
#define LCD_SCL GPIO_Pin_13 //PB13--->>TFT --SCL/SCK
#define LCD_SDA GPIO_Pin_15 //PB15 MOSI--->>TFT --SDA/DIN
//#define LCD_CS_SET(x) LCD_CTRL->ODR=(LCD_CTRL->ODR&~LCD_CS)|(x ? LCD_CS:0)
//液晶控制口置1操作语句宏定义
#define LCD_CS_SET LCD_CTRL->BSRR=LCD_CS
#define LCD_RS_SET LCD_CTRL->BSRR=LCD_RS
#define LCD_SDA_SET LCD_CTRL->BSRR=LCD_SDA
#define LCD_SCL_SET LCD_CTRL->BSRR=LCD_SCL
#define LCD_RST_SET LCD_CTRL->BSRR=LCD_RST
#define LCD_LED_SET LCD_CTRL->BSRR=LCD_LED
//液晶控制口置0操作语句宏定义
#define LCD_CS_CLR LCD_CTRL->BRR=LCD_CS
#define LCD_RS_CLR LCD_CTRL->BRR=LCD_RS
#define LCD_SDA_CLR LCD_CTRL->BRR=LCD_SDA
#define LCD_SCL_CLR LCD_CTRL->BRR=LCD_SCL
#define LCD_RST_CLR LCD_CTRL->BRR=LCD_RST
#define LCD_LED_CLR LCD_CTRL->BRR=LCD_LED
#define LCD_DATAOUT(x) LCD_DATA->ODR=x; //数据输出
#define LCD_DATAIN LCD_DATA->IDR; //数据输入
#define LCD_WR_DATA(data){\
LCD_RS_SET;\
LCD_CS_CLR;\
LCD_DATAOUT(data);\
LCD_WR_CLR;\
LCD_WR_SET;\
LCD_CS_SET;\
}
void LCD_GPIO_Init(void);
void Lcd_WriteIndex(u8 Index);
void Lcd_WriteData(u8 Data);
void Lcd_WriteReg(u8 Index,u8 Data);
u16 Lcd_ReadReg(u8 LCD_Reg);
void Lcd_Reset(void);
void Lcd_Init(u8 dir);
void Lcd_Clear(u16 Color);
void Lcd_SetXY(u16 x,u16 y);
void Gui_DrawPoint(u16 x,u16 y,u16 Data);
unsigned int Lcd_ReadPoint(u16 x,u16 y);
Lcd_Config.h文件:
#define X_MAX_PIXEL 128
#define Y_MAX_PIXEL 160
GUI.c文件:(这是TFT在Lcd_Driver.c文件在基础上已经封装好的UI操作函数)
#include "stm32f10x.h"
#include "Lcd_Driver.h"
#include "GUI.h"
#include "delay.h"
#include "font.h"
#include "Picture.h"
unsigned char Num[10]={0,1,2,3,4,5,6,7,8,9};
//从ILI93xx读出的数据为GBR格式,而我们写入的时候为RGB格式。
//通过该函数转换
//c:GBR格式的颜色值
//返回值:RGB格式的颜色值
u16 LCD_BGR2RGB(u16 c)
{
u16 r,g,b,rgb;
b=(c>>0)&0x1f;
g=(c>>5)&0x3f;
r=(c>>11)&0x1f;
rgb=(b<<11)+(g<<5)+(r<<0);
return(rgb);
}
void Gui_Circle(u16 X,u16 Y,u16 R,u16 fc)
{//Bresenham算法
unsigned short a,b;
int c;
a=0;
b=R;
c=3-2*R;
while (a<b)
{
Gui_DrawPoint(X+a,Y+b,fc); // 7
Gui_DrawPoint(X-a,Y+b,fc); // 6
Gui_DrawPoint(X+a,Y-b,fc); // 2
Gui_DrawPoint(X-a,Y-b,fc); // 3
Gui_DrawPoint(X+b,Y+a,fc); // 8
Gui_DrawPoint(X-b,Y+a,fc); // 5
Gui_DrawPoint(X+b,Y-a,fc); // 1
Gui_DrawPoint(X-b,Y-a,fc); // 4
if(c<0) c=c+4*a+6;
else
{
c=c+4*(a-b)+10;
b-=1;
}
a+=1;
}
if (a==b)
{
Gui_DrawPoint(X+a,Y+b,fc);
Gui_DrawPoint(X+a,Y+b,fc);
Gui_DrawPoint(X+a,Y-b,fc);
Gui_DrawPoint(X-a,Y-b,fc);
Gui_DrawPoint(X+b,Y+a,fc);
Gui_DrawPoint(X-b,Y+a,fc);
Gui_DrawPoint(X+b,Y-a,fc);
Gui_DrawPoint(X-b,Y-a,fc);
}
}
//画线函数,使用Bresenham 画线算法
void Gui_DrawLine(u16 x0, u16 y0,u16 x1, u16 y1,u16 Color)
{
int dx, // difference in x's
dy, // difference in y's
dx2, // dx,dy * 2
dy2,
x_inc, // amount in pixel space to move during drawing
y_inc, // amount in pixel space to move during drawing
error, // the discriminant i.e. error i.e. decision variable
index; // used for looping
Lcd_SetXY(x0,y0);
dx = x1-x0;//计算x距离
dy = y1-y0;//计算y距离
if (dx>=0)
{
x_inc = 1;
}
else
{
x_inc = -1;
dx = -dx;
}
if (dy>=0)
{
y_inc = 1;
}
else
{
y_inc = -1;
dy = -dy;
}
dx2 = dx << 1;
dy2 = dy << 1;
if (dx > dy)//x距离大于y距离,那么每个x轴上只有一个点,每个y轴上有若干个点
{//且线的点数等于x距离,以x轴递增画点
// initialize error term
error = dy2 - dx;
// draw the line
for (index=0; index <= dx; index++)//要画的点数不会超过x距离
{
//画点
Gui_DrawPoint(x0,y0,Color);
// test if error has overflowed
if (error >= 0) //是否需要增加y坐标值
{
error-=dx2;
// move to next line
y0+=y_inc;//增加y坐标值
} // end if error overflowed
// adjust the error term
error+=dy2;
// move to the next pixel
x0+=x_inc;//x坐标值每次画点后都递增1
} // end for
} // end if |slope| <= 1
else//y轴大于x轴,则每个y轴上只有一个点,x轴若干个点
{//以y轴为递增画点
// initialize error term
error = dx2 - dy;
// draw the line
for (index=0; index <= dy; index++)
{
// set the pixel
Gui_DrawPoint(x0,y0,Color);
// test if error overflowed
if (error >= 0)
{
error-=dy2;
// move to next line
x0+=x_inc;
} // end if error overflowed
// adjust the error term
error+=dx2;
// move to the next pixel
y0+=y_inc;
} // end for
} // end else |slope| > 1
}
void Gui_box(u16 x, u16 y, u16 w, u16 h,u16 bc)
{
Gui_DrawLine(x,y,x+w,y,0xEF7D);
Gui_DrawLine(x+w-1,y+1,x+w-1,y+1+h,0x2965);
Gui_DrawLine(x,y+h,x+w,y+h,0x2965);
Gui_DrawLine(x,y,x,y+h,0xEF7D);
Gui_DrawLine(x+1,y+1,x+1+w-2,y+1+h-2,bc);
}
void Gui_box2(u16 x,u16 y,u16 w,u16 h, u8 mode)
{
if (mode==0) {
Gui_DrawLine(x,y,x+w,y,0xEF7D);
Gui_DrawLine(x+w-1,y+1,x+w-1,y+1+h,0x2965);
Gui_DrawLine(x,y+h,x+w,y+h,0x2965);
Gui_DrawLine(x,y,x,y+h,0xEF7D);
}
if (mode==1) {
Gui_DrawLine(x,y,x+w,y,0x2965);
Gui_DrawLine(x+w-1,y+1,x+w-1,y+1+h,0xEF7D);
Gui_DrawLine(x,y+h,x+w,y+h,0xEF7D);
Gui_DrawLine(x,y,x,y+h,0x2965);
}
if (mode==2) {
Gui_DrawLine(x,y,x+w,y,0xffff);
Gui_DrawLine(x+w-1,y+1,x+w-1,y+1+h,0xffff);
Gui_DrawLine(x,y+h,x+w,y+h,0xffff);
Gui_DrawLine(x,y,x,y+h,0xffff);
}
}
/**************************************************************************************
功能描述: 在屏幕显示一凸起的按钮框
输 入: u16 x1,y1,x2,y2 按钮框左上角和右下角坐标
输 出: 无
**************************************************************************************/
void DisplayButtonDown(u16 x1,u16 y1,u16 x2,u16 y2)
{
Gui_DrawLine(x1, y1, x2,y1, GRAY2); //H
Gui_DrawLine(x1+1,y1+1,x2,y1+1, GRAY1); //H
Gui_DrawLine(x1, y1, x1,y2, GRAY2); //V
Gui_DrawLine(x1+1,y1+1,x1+1,y2, GRAY1); //V
Gui_DrawLine(x1, y2, x2,y2, WHITE); //H
Gui_DrawLine(x2, y1, x2,y2, WHITE); //V
}
/**************************************************************************************
功能描述: 在屏幕显示一凹下的按钮框
输 入: u16 x1,y1,x2,y2 按钮框左上角和右下角坐标
输 出: 无
**************************************************************************************/
void DisplayButtonUp(u16 x1,u16 y1,u16 x2,u16 y2)
{
Gui_DrawLine(x1, y1, x2,y1, WHITE); //H
Gui_DrawLine(x1, y1, x1,y2, WHITE); //V
Gui_DrawLine(x1+1,y2-1,x2,y2-1, GRAY1); //H
Gui_DrawLine(x1, y2, x2,y2, GRAY2); //H
Gui_DrawLine(x2-1,y1+1,x2-1,y2, GRAY1); //V
Gui_DrawLine(x2 ,y1 ,x2,y2, GRAY2); //V
}
void Gui_DrawFont_GBK16(u16 x, u16 y, u16 fc, u16 bc, char *s)
{
unsigned char i,j;
unsigned short k,x0;
x0=x;
while(*s)
{
if((*s) < 128)
{
k=*s;
if (k==13)
{
x=x0;
y+=16;
}
else
{
if (k>32) k-=32; else k=0;
for(i=0;i<16;i++)
for(j=0;j<8;j++)
{
if(asc16[k*16+i]&(0x80>>j)) Gui_DrawPoint(x+j,y+i,fc);
else
{
if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc);
}
}
x+=8;
}
s++;
}
else
{
for (k=0;k<hz16_num;k++)
{
if ((hz16[k].Index[0]==*(s))&&(hz16[k].Index[1]==*(s+1)))
{
for(i=0;i<16;i++)
{
for(j=0;j<8;j++)
{
if(hz16[k].Msk[i*2]&(0x80>>j)) Gui_DrawPoint(x+j,y+i,fc);
else {
if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc);
}
}
for(j=0;j<8;j++)
{
if(hz16[k].Msk[i*2+1]&(0x80>>j)) Gui_DrawPoint(x+j+8,y+i,fc);
else
{
if (fc!=bc) Gui_DrawPoint(x+j+8,y+i,bc);
}
}
}
}
}
s+=2;x+=16;
}
}
}
void Gui_DrawFont_GBK24(u16 x, u16 y, u16 fc, u16 bc, u8 *s)
{
unsigned char i,j;
unsigned short k;
while(*s)
{
if( *s < 0x80 )
{
k=*s;
if (k>32) k-=32; else k=0;
for(i=0;i<16;i++)
for(j=0;j<8;j++)
{
if(asc16[k*16+i]&(0x80>>j))
Gui_DrawPoint(x+j,y+i,fc);
else
{
if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc);
}
}
s++;x+=8;
}
else
{
for (k=0;k<hz24_num;k++)
{
if ((hz24[k].Index[0]==*(s))&&(hz24[k].Index[1]==*(s+1)))
{
for(i=0;i<24;i++)
{
for(j=0;j<8;j++)
{
if(hz24[k].Msk[i*3]&(0x80>>j))
Gui_DrawPoint(x+j,y+i,fc);
else
{
if (fc!=bc) Gui_DrawPoint(x+j,y+i,bc);
}
}
for(j=0;j<8;j++)
{
if(hz24[k].Msk[i*3+1]&(0x80>>j)) Gui_DrawPoint(x+j+8,y+i,fc);
else {
if (fc!=bc) Gui_DrawPoint(x+j+8,y+i,bc);
}
}
for(j=0;j<8;j++)
{
if(hz24[k].Msk[i*3+2]&(0x80>>j))
Gui_DrawPoint(x+j+16,y+i,fc);
else
{
if (fc!=bc) Gui_DrawPoint(x+j+16,y+i,bc);
}
}
}
}
}
s+=2;x+=24;
}
}
}
void Gui_DrawFont_Num32(u16 x, u16 y, u16 fc, u16 bc, u16 num)
{
unsigned char i,j,k,c;
//lcd_text_any(x+94+i*42,y+34,32,32,0x7E8,0x0,sz32,knum[i]);
// w=w/8;
for(i=0;i<32;i++)
{
for(j=0;j<4;j++)
{
c=*(sz32+num*32*4+i*4+j);
for (k=0;k<8;k++)
{
if(c&(0x80>>k)) Gui_DrawPoint(x+j*8+k,y+i,fc);
else {
if (fc!=bc) Gui_DrawPoint(x+j*8+k,y+i,bc);
}
}
}
}
}
void Redraw_Mainmenu(void)
{
Lcd_Clear(GRAY0);
Gui_DrawFont_GBK16(16,0,BLUE,GRAY0,"全动电子技术");
Gui_DrawFont_GBK16(16,20,RED,GRAY0,"液晶测试程序");
DisplayButtonUp(15,38,113,58); //x1,y1,x2,y2
Gui_DrawFont_GBK16(16,40,YELLOW,GRAY0,"颜色填充测试");
DisplayButtonUp(15,68,113,88); //x1,y1,x2,y2
Gui_DrawFont_GBK16(16,70,BLUE,GRAY0,"文字显示测试");
DisplayButtonUp(15,98,113,118); //x1,y1,x2,y2
Gui_DrawFont_GBK16(16,100,RED,GRAY0,"图片显示测试");
Gui_DrawFont_GBK16(16,120,BLUE,GRAY0,"S1:Move. ");
Gui_DrawFont_GBK16(16,140,RED,GRAY0, "S2:Sellect ");
Gui_DrawFont_Num32(100,125,RED,GRAY0,Num[5]);
delay_ms(1000);
Gui_DrawFont_Num32(100,125,RED,GRAY0,Num[4]);
delay_ms(1000);
Gui_DrawFont_Num32(100,125,RED,GRAY0,Num[3]);
delay_ms(1000);
Gui_DrawFont_Num32(100,125,RED,GRAY0,Num[2]);
delay_ms(1000);
Gui_DrawFont_Num32(100,125,RED,GRAY0,Num[1]);
delay_ms(1000);
Gui_DrawFont_Num32(100,125,RED,GRAY0,Num[0]);
}
void Num_Test(void)
{
u8 i=0;
Lcd_Clear(GRAY0);
Gui_DrawFont_GBK16(16,20,RED,GRAY0,"Num Test");
delay_ms(1000);
Lcd_Clear(GRAY0);
for(i=0;i<10;i++)
{
Gui_DrawFont_Num32((i%3)*40,32*(i/3)+30,RED,GRAY0,Num[i+1]);
delay_ms(100);
}
}
void Font_Test(void)
{
Lcd_Clear(GRAY0);
Gui_DrawFont_GBK16(16,10,BLUE,GRAY0,"文字显示测试");
delay_ms(1000);
Lcd_Clear(GRAY0);
Gui_DrawFont_GBK16(16,30,YELLOW,GRAY0,"全动电子技术");
Gui_DrawFont_GBK16(16,50,BLUE,GRAY0,"专注液晶批发");
Gui_DrawFont_GBK16(16,70,RED,GRAY0, "全程技术支持");
Gui_DrawFont_GBK16(0,100,BLUE,GRAY0,"Tel:15989313508");
Gui_DrawFont_GBK16(0,130,RED,GRAY0, "www.qdtech.net");
delay_ms(1800);
}
void Color_Test(void)
{
u8 i=1;
Lcd_Clear(GRAY0);
Gui_DrawFont_GBK16(20,10,BLUE,GRAY0,"Color Test");
delay_ms(200);
while(i--)
{
Lcd_Clear(WHITE);
Lcd_Clear(BLACK);
Lcd_Clear(RED);
Lcd_Clear(GREEN);
Lcd_Clear(BLUE);
}
}
//16位 垂直扫描 右到左 高位在前
void show_pic(void)
{
int i,j,k;
unsigned char picH,picL;
Lcd_Clear(GRAY0);
Gui_DrawFont_GBK16(16,10,BLUE,GRAY0,"图片显示测试");
delay_ms(1000);
Lcd_Clear(GRAY0);
k=0;
for(i=0;i<128;i++)
for(j=0;j<160;j++)
{
picH=gImage_123[k++];
picL=gImage_123[k++];
Lcd_WriteData(picH);
Lcd_WriteData(picL);
}
}
GUI.h文件:
u16 LCD_BGR2RGB(u16 c);
void Gui_Circle(u16 X,u16 Y,u16 R,u16 fc);
void Gui_DrawLine(u16 x0, u16 y0,u16 x1, u16 y1,u16 Color);
void Gui_box(u16 x, u16 y, u16 w, u16 h,u16 bc);
void Gui_box2(u16 x,u16 y,u16 w,u16 h, u8 mode);
void DisplayButtonDown(u16 x1,u16 y1,u16 x2,u16 y2);
void DisplayButtonUp(u16 x1,u16 y1,u16 x2,u16 y2);
void Gui_DrawFont_GBK16(u16 x, u16 y, u16 fc, u16 bc, char *s);
void Gui_DrawFont_GBK24(u16 x, u16 y, u16 fc, u16 bc, u8 *s);
void Gui_DrawFont_Num32(u16 x, u16 y, u16 fc, u16 bc, u16 num) ;
void Redraw_Mainmenu(void);
void Num_Test(void);
void Font_Test(void);
void Color_Test(void);
void show_pic(void);
main.c文件:
#include "stm32f10x.h"
#include <math.h> //Keil library
#include <stdio.h> //Keil library
#include "Delay.H"
#include "Lcd_Driver.h"
#include "GUI.h"
#include "DS1302.H"
extern char DS1302_data_1[10];//当前时间
extern char DS1302_data_2[8];//当前时间
int main(void)
{
SystemInit();
delay_init(72);//延时初始化
//-----------------------------------------------------------
Lcd_Init(0);//LCD初始化
LCD_LED_SET;//通过IO控制背光亮
Lcd_Clear(GRAY0);//LCD清屏
//-----------------------------------------------------------
ds1302_gpio_init();delay_ms(5); //初始化ds1302端口
//ds1032_init();delay_ms(5); //ds1302初始化,用于第一次使用DS1302,赋时间初值
ds1302_read_realTime(); //读取实时数据
min=TimeData.minute; //记录此时分钟值
while(1)
{
//DS1302读取数据,TFT屏幕显示
ds1302_read_realTime(); //读取此时时刻
Gui_DrawFont_GBK16(1,100,BLUE,GRAY0,DS1302_data_1);//TFT屏幕显示DS1302数据
Gui_DrawFont_GBK16(1,120,BLUE,GRAY0,DS1302_data_2);//TFT屏幕显示DS1302数据
}
}
四.新手可能会遇到的疑点:
1.TFT屏幕显示内容或者串口输出内容有时候是需要发送字符串的,但如果需要发送的变量是整型而不是字符型,该怎么把整型数据转化为字符串呢?
可采用DS1302.c中的一个笨方法,如图:
这里涉及到的算法有C语言中的:提取多位数中的各个位数(取余,取整思想),还有单字符的加减法。(详细教程请参考其他资料)
提取多位数中的各个位数(取余,取整思想):
int a,b,c,d,e;
a=1234;
b=a/1000;
c=a/100%10;
d=a/10%10;
e=a%10;
如上所示,该代码结果b=1,c=2,d=3,e=4。
单字符的加减法:
char a;
a='0'+4;
如上所示,该代码结果会得到字符a='4'。
2.关于DS1302初始时间怎么设置的问题,如图:
该函数的作用是为DS1302写入初始时间,一般这个函数只会在你第一次使用DS1302模块或者更新模块时间时使用。而改变它初始时间的方法就是将初始的、年、月、日、时、分、秒、周用16进制写入上图标荧光的地方。
或者为了方便,也可以将函数中的年月日时分秒周单独放入一个数组中,然后在函数中调用数组就可以了
unsigned int DS1302_start_Data[7]={0x22,0x01,0x19,0x21,0x03,0x00,0x07};//年月日时分秒周
void ds1302_init()
{
ds1302_wirte_rig(0x8e,0x00);//关闭写保护
ds1302_wirte_rig(0x80,DS1302_start_Data[5]);//seconds 0秒
ds1302_wirte_rig(0x82,DS1302_start_Data[4]);//minutes 03分
ds1302_wirte_rig(0x84,DS1302_start_Data[3]);//hours 21时
ds1302_wirte_rig(0x86,DS1302_start_Data[2]);//date 19日
ds1302_wirte_rig(0x88,DS1302_start_Data[1]);//months 1月
ds1302_wirte_rig(0x8a,DS1302_start_Data[6]);//days 星期日
ds1302_wirte_rig(0x8c,DS1302_start_Data[0]);//year 2022年
ds1302_wirte_rig(0x8e,0x80);//关闭写保护
}
(这是本人发表的第一篇文章,望大家给予宝贵的建议)