一、驱动原理
1.HT1621原理
①中文技术手册:中文版HT1621B
②根据技术手册上的时序图分析出HT1621驱动的基本流程
CS-WR-DATA引脚初始化(设置为推挽输出模式)➡CS引脚置低(片选使能)➡DATA线写命令(发送100进入命令模式)➡DATA线写地址➡DATA线写数据➡CS引脚置高➡结束
二、驱动代码
#include "stm32f10x.h"
#include "CS1621.h"
#include "Delay.h"
/*
********************************************************************
io口初始化,因为PB3,PB4,PA14,PA15是特殊调试引脚,要当成正常io口使用:
1、打开复用时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
2、对三个引脚进行重映射:
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
三个引脚重映射后不可以再次初始化复用时钟,否则PA15、PB4、PB3三个引脚会重新变回调试引脚。因此此初始化要放在最后一个执行
即不能再调用
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
*********************************************************************
*/
/*
*********************************************************************
函数:void HT1621_Init(void)
功能:HT1621引脚初始化:
CS -- PA15
WR -- PB3
DATA -- PB5
*********************************************************************
*/
void HT1621_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//CS
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //WR
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//DATA
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*
******************************************************************************
LCD_Init
初始化命令到HT1621
******************************************************************************
*/
void LCD_Init(void)
{
WriteCmdtoHT1621(0x02);//打开系统振荡器
WriteCmdtoHT1621(0x06);//打开LCD偏压
WriteCmdtoHT1621(0x30);//启用内部时钟
WriteCmdtoHT1621(0x50);/// ;CD1/2偏执,4com
}
/*
******************************************************************************
WriteDatatoHT1621
写数据到HT1621
Data:要写入的数据bits num:传送数据位数
******************************************************************************
*/
void WriteDatatoHT1621(u8 Data,u8 num)
{
u8 i;
for (i=0;i<num;i++)
{
GPIO_ResetBits(GPIOB, GPIO_Pin_3) //拉低WR脚 Data线上的数据在WR脚位上升沿写入
if(Data & 0x80)//判断高位是否为1,如果是1就输出高电平,否则低电平
{
GPIO_SetBits(GPIOB, GPIO_Pin_5)//拉高DATA(开始写入数据)
}
else
{
GPIO_ResetBits(GPIOB, GPIO_Pin_5) //拉低DATA
}
GPIO_SetBits(GPIOB, GPIO_Pin_3)//当前这一bit写完,拉高WR脚,为下次WR为上升沿做准备
Data<<=1; //当前位用完了,移到下一位继续上述动作
}
}
/*
******************************************************************************
WritetoHT1621
将要显示的数据写到HT1621
Addr:写入初始地址,Data:写入数据
******************************************************************************
*/
void WritetoHT1621(u8 Addr,u8 Data)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_15) //拉高CS 开始写数据
WriteDatatoHT1621(0xa0,3); //写入0x80 /0xa0
WriteDatatoHT1621(Addr<<2,6);//写入地址
WriteDatatoHT1621(Data<<4,4);//写入数据 这里是对应单个SEG写的 故而为4
GPIO_SetBits(GPIOA, GPIO_Pin_15)// 拉高CS 结束
}
/*
******************************************************************************
WriteCmdtoHT1621
写命令到HT1621
Cmd:命令
******************************************************************************
*/
void WriteCmdtoHT1621(u8 Cmd)
{
GPIO_ResetBits(GPIOA, GPIO_Pin_15) //拉低CS脚 CS拉低时WR有效
WriteDatatoHT1621(WrCmd,4);//写入命令标志100 0x80 3
WriteDatatoHT1621(Cmd,8); //写入命令数据
WriteDatatoHT1621(0,1);
GPIO_SetBits(GPIOA, GPIO_Pin_15)// 拉高CS 结束
}
/*
******************************************************************************
CleanUpLCD
清屏
******************************************************************************
*/
void CleanUpLCD(void)
{
uint8_t j;
for(j=0;j<30;j++)
{
WritetoHT1621(j, 0x00);//清屏
}
}
三、显示函数(可以确定未知屏的断码值)
1.可以实现逐个显示每一段,全部显示完成5s后清屏;
#include "stm32f10x.h"
#include "CS1621.h"
uint8_t c;
int main(void)
{
Timer_Init();//定时器初始化
HT1621_Init();//屏幕初始化
LCD_Init();
while (1)
{
for(c=0;c<=30;c++)//30指的是:所用的地址总数,可以根据自己的实际情况修改
{
WritetoHT1621(c, 0x01);
Delay_ms (500);
WritetoHT1621(c, 0x01 | 0x02);
Delay_ms (500);
WritetoHT1621(c, 0x01 | 0x02 | 0x04);
Delay_ms (500);
WritetoHT1621(c, 0x01 | 0x02 | 0x04 | 0x08);
Delay_ms (500);
}
Delay_ms (5000);
CleanUpLCD();//清屏函数
}
}
/*
函数:void Delay_us(uint32_t xus)
功能:微秒延时
*/
void Delay_us(uint32_t xus)
{
SysTick->LOAD = 72 * xus; //设置定时器重装值
SysTick->VAL = 0x00; //清空当前计数值
SysTick->CTRL = 0x00000005; //设置时钟源为HCLK,启动定时器
while(!(SysTick->CTRL & 0x00010000)); //等待计数到0
SysTick->CTRL = 0x00000004; //关闭定时器
}
/*
函数:void Delay_ms(uint32_t xms)
功能:毫秒延时
*/
void Delay_ms(uint32_t xms)
{
while(xms--)
{
Delay_us(1000);
}
}
2.根据段码值,编写正常显示的数据(例:基本数字显示)
根据上述段码值,如果左边一个数显示0,那么SEG24➡1111➡F;SEG25➡0101➡5;因此可以先写出次数显的数码表(显示0-9){0➡0xf5;1➡0x60;2➡0xb6;3➡0xf2;4➡0x63;5➡0xd3;6➡0xd7;7➡0x70;8➡0xf7;9➡0xf3;}
程序中就可以以此先定义一个数码表数组:
u8 SegCode[10] = {
// 数字显示0-9,任何显示数字的区域,都是调用这里的数据
0Xf5, // 0
0X60, // 1
0Xb6, // 2
0XF2, // 3
0X63, // 4
0XD3, // 5
0XD7, // 6
0X70, // 7
0XF7, // 8
0XF3 // 9
};
3.根据数码表,实时显示一直变化的数据
因为我的完整程序中有很多要显示的片段,为了防止命名重复,便于分辨,我这里用的是一个结构体。(结构体具体用法这里就不做过多阐述了),话不多说,看代码;
struct datetype_LCD_Information //定义一个名为LCD_Information结构体
{
int RechagingTime; //可使用时间
}LCD_Information;
extern struct datetype_LCD_Information LCD_Information;//全局定义后可以在任意子函数调用次结构体变量;
/*
*****************************************************************
名称:void LCD_Display(void)
功能:显示屏显示内容
*****************************************************************
*/
void LCD_Display(void)
{
u8 i;
uint16_t tens; // 十位
uint16_t ones; // 个位
uint16_t hundreds; // 百位
uint16_t thousands; // 千位
for (i = 0; i < 30; i++) // 初始化 清屏 这个不能少,否则会有异常显示
{
LCD_SEG[i] = 0;
}
// 充电时间显示
Rech_Time();
tens = LCD_Information.RechagingTime % 100 / 10;
ones = LCD_Information.RechagingTime % 10;
//根据段码屏的真值表可以判断出:要显示一个完整的数字,需要分别控制高四位和低四位;
// 十位
LCD_SEG[28] = SegCode[tens];//低四位
LCD_SEG[26] = SegCode[tens] >> 4;//高四位
// 个位
LCD_SEG[25] = SegCode[ones];//低四位
LCD_SEG[24] = SegCode[ones] >> 4;//高四位
}
上面的准备工作完成后,就可以把LCD_Display();这个函数放在定时器里面,一直刷新数据。只要我们更改LCD_Information.RechagingTime的数值,显示屏上就会显示我们最终显示的数字。
PS:不一定用结构体;也可以随便定义一个全局变量,最终显示的效果都是一样的。
结尾
初次学习,有不正确的地方还请大佬们指正。