STM32F103单片机控制HT1621驱动学习记录及未知屏断码值查询方法

一、驱动原理

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:不一定用结构体;也可以随便定义一个全局变量,最终显示的效果都是一样的。

结尾

初次学习,有不正确的地方还请大佬们指正。

物联沃分享整理
物联沃-IOTWORD物联网 » STM32F103单片机控制HT1621驱动学习记录及未知屏断码值查询方法

发表评论