CH455是一款用于驱动数码管(LED)和矩阵键盘扫描控制芯片。能够动态驱动4位数码管或者32个LED。同时支持7x4的键盘扫描。单片机通过I2C对CH455进行读写,同时包括一个#INT中断引脚,任何一个按键按下都会触发中断,在INT引脚上产生低电平脉冲。
CH455内部的显示驱动电路和按键扫描电路是独立开的,两部分电路使用相同的引脚,分时对引脚进行驱动和读取。在显示驱动中,插入键盘键值读取操作。
显示驱动原理与HT1612段码屏驱动原理类似,都是以SEG[n:0]和DIG[m:0]分别作为行、列,组成一个寄存器矩阵,一共(n+1)*(m+1)位数据。将单个LED要显示的状态对应写进寄存器,芯片内部电路会按照寄存器中数据进行动态扫描输出。
CH455对数码管和LED采用动态扫描驱动,顺序为DIG0~DIG3,当其中一个引脚吸入电流时,其他引脚不吸入电流。
如下图中,若硬件上将SEG0~7的公共端接到DIG0时,若要左侧共阴数码管显示0,在要在SEG0地址寄存器中写入0B00111111,即0x3F。芯片会按照寄存器的值来驱动左侧数码管显示。
寄存器地址:
键盘扫描时,DIG3~DIG0引脚用于列扫描输出,SEG6~SEG0引脚带有内部下拉电阻,用于行扫描输入。在键盘扫描期间,DIG0~DIG3一次输出高电平,其余引脚输出低电平,该状态下SEG0~SEG6引脚的输出被禁止。 CH455内部带有消抖功能,连续两次判断有按键按下才会被确认。当检测到按键后,会讲按键值存储在寄存器中,并在#INT引脚上产生低电平中断。
注:当多个按键按下时,按键码较小的按键优先。
按键码格式:bit7一直为0, bit2一直为1,bit[1:0]为列扫描码,bit[5:3]为行扫描码,bit6位状态码(按键按下为1,按键松开为0,判断该位的值来判断按键是否松开)。如连接DIG2和SEG5的按键被按下,则bit[1:0]=10,bit[5:3]=101,bit6=1,有
Key = 0B01101110 (0x6E)
对应按键码如下,因为按下立即读键码寄存器是bit6=1,所以需要在按键编码上加上0x40
系统参数主要包括,显示驱动电路和键盘扫描使能,7/8段模式,8阶亮度控制,sleep模式。系统参数有一个字节控制,其中bit7和bit1一直为0,bit[6:4]控制亮度显示(000为8/8,001~111为1/8~7/8亮度),bit3控制7/8模式(0为8段,1为7段),bit2为sleep模式(写1使能,可通过按键唤醒或者操作指令唤醒),bit0为使能(高电平有效)。
如需要让CH455工作在8段,最亮的情况下,则该值为0B00000001,,即0x01。
总的来说,实际上只要对6个寄存器进行操作就行。
下列为STM32应用代码,已经验证能够稳定使用,留言询问后方可转载。
ch455.h
#ifndef __CH455_H
#define __CH455_H
#include "sys.h"
typedef unsigned char UINT8;
typedef unsigned short UINT16;
#define high 1
#define low 0
/* 2线接口的连接,与实际电路有关 */
#define CH455_SCL PBout(4) //SCL
#define CH455_SDA PBout(5) //SDA
/* 2线接口的位操作,与单片机有关 */
#define CH455_SCL_SET {CH455_SCL=1;}
#define CH455_SCL_CLR {CH455_SCL=0;}
#define CH455_SCL_D_OUT {GPIOB->CRL&=0XFFF0FFFF;GPIOB->CRL|=(u32)3<<(4*4);} // 设置SCL为输出方向,对于双向I/O需切换为输出
#define CH455_SDA_SET {CH455_SDA=1;}
#define CH455_SDA_CLR {CH455_SDA=0;}
#define CH455_SDA_IN GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5) // 读取SDA输入电平
#define CH455_SDA_D_OUT {GPIOB->CRL&=0XFF0FFFFF;GPIOB->CRL|=(u32)3<<(5*4);} // 设置SDA为输出方向,对于双向I/O需切换为输出
#define CH455_SDA_D_IN {GPIOB->CRL&=0XFF0FFFFF;GPIOB->CRL|=(u32)8<<(5*4);} // 设置SDA为输入方向,对于双向I/O需切换为输入
/* ********************************************************************************************* */
// 设置系统参数命令
#define CH455_BIT_ENABLE 0x01 // 开启/关闭位
#define CH455_BIT_SLEEP 0x04 // 睡眠控制位
#define CH455_BIT_7SEG 0x08 // 7段控制位
#define CH455_BIT_INTENS1 0x10 // 1级亮度
#define CH455_BIT_INTENS2 0x20 // 2级亮度
#define CH455_BIT_INTENS3 0x30 // 3级亮度
#define CH455_BIT_INTENS4 0x40 // 4级亮度
#define CH455_BIT_INTENS5 0x50 // 5级亮度
#define CH455_BIT_INTENS6 0x60 // 6级亮度
#define CH455_BIT_INTENS7 0x70 // 7级亮度
#define CH455_BIT_INTENS8 0x00 // 8级亮度
#define CH455_SYSOFF 0x0400 // 关闭显示、关闭键盘
#define CH455_SYSON ( CH455_SYSOFF | CH455_BIT_ENABLE ) // 开启显示、键盘
#define CH455_SLEEPOFF CH455_SYSOFF // 关闭睡眠
#define CH455_SLEEPON ( CH455_SYSOFF | CH455_BIT_SLEEP ) // 开启睡眠
#define CH455_7SEG_ON ( CH455_SYSON | CH455_BIT_7SEG ) // 开启七段模式
#define CH455_8SEG_ON ( CH455_SYSON | 0x00 ) // 开启八段模式
#define CH455_SYSON_4 ( CH455_SYSON | CH455_BIT_INTENS4 ) // 开启显示、键盘、4级亮度
#define CH455_SYSON_8 ( CH455_SYSON | CH455_BIT_INTENS8 ) // 开启显示、键盘、8级亮度
// 加载字数据命令
#define CH455_DIG0 0x1400 // 数码管位0显示,需另加8位数据
#define CH455_DIG1 0x1500 // 数码管位1显示,需另加8位数据
#define CH455_DIG2 0x1600 // 数码管位2显示,需另加8位数据
#define CH455_DIG3 0x1700 // 数码管位3显示,需另加8位数据
// 读取按键代码命令
#define CH455_GET_KEY 0x0700 // 获取按键,返回按键代码
// CH455接口定义
#define CH455_I2C_ADDR 0x40 // CH455的地址
#define CH455_I2C_MASK 0x3E // CH455的高字节命令掩码
// 对外子程序
extern void CH455_Init(void); //初始化函数
extern UINT8 CH455_Read( void ); // 从CH455读取按键代码
extern void CH455_Write( UINT16 cmd ); // 向CH455发出操作命令
UINT8 CH455_I2c_RdByte( void );
void CH455_I2c_WrByte(unsigned char IIC_Byte);
void CH455_I2c_Stop();
void CH455_I2c_Start();
#endif /* CH455_H */
ch455.c
/*
* File: CH455.c
* Author: JiangXiaowei
*/
#include "ch455.h" // 修改该文件以适应硬件环境/单片机型号等
#include "delay.h"
//定义
#define I2C_DELAY 5
void CH455_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE ); //使能GPIOB时钟
//stm32f103中PB3、PB4、PA15为JTAG引脚,若要作为普通IO口来使用的话,要禁用JTAG功能。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_4|GPIO_Pin_5);
CH455_Write( CH455_SYSON_8 ); //八段式
}
/*
* 函数功能:IIC产生起始信号函数
* 输入参数:无
* 输出参数:无
*/
void CH455_I2c_Start()
{
CH455_SDA_D_OUT;
CH455_SCL = high; //SCL = high;
DelayUs(I2C_DELAY);
CH455_SDA = high; //SDA = high;
DelayUs(I2C_DELAY);
CH455_SDA = low; //SDA = low;
DelayUs(I2C_DELAY);
CH455_SCL = low; //SCL = low;
DelayUs(I2C_DELAY);
}
/*
* 函数功能:IIC产生停止信号
* 输入参数:无
* 输出参数:无
*/
void CH455_I2c_Stop()
{
CH455_SDA_D_OUT;
CH455_SCL = low; //SCL = low;
DelayUs(I2C_DELAY);
CH455_SDA = low; //SDA = low;
DelayUs(I2C_DELAY);
CH455_SCL = high; //SCL = high;
DelayUs(I2C_DELAY);
CH455_SDA = high; //SDA = high;
DelayUs(I2C_DELAY);
}
/*
* 函数功能:IIC发送一个字节
* 输入参数:一个字节
* 输出参数:无
*/
void CH455_I2c_WrByte(unsigned char IIC_Byte)
{
unsigned char i;
CH455_SDA_D_OUT;
for(i = 0; i < 8; i++)
{
if(IIC_Byte & 0x80)
CH455_SDA = high; //SDA=high;
else
CH455_SDA = low; //SDA=low;
DelayUs(I2C_DELAY);
CH455_SCL = high; //SCL=high;
DelayUs(I2C_DELAY);
CH455_SCL = low; //SCL=low;
DelayUs(I2C_DELAY);
IIC_Byte<<=1;
}
DelayUs(I2C_DELAY);
CH455_SDA = high; //SDA=1;
DelayUs(I2C_DELAY);
CH455_SCL = high; //SCL=1;
DelayUs(I2C_DELAY);
CH455_SCL = low; //SCL=0;
DelayUs(I2C_DELAY);
}
unsigned char CH455_I2c_RdByte( void ) //读一个字节数据
{
unsigned char i, bytedata;
CH455_SDA_D_IN; //将数据设置为输入模式
DelayUs(I2C_DELAY);
CH455_SDA = 1; //数据线拉高
DelayUs(I2C_DELAY);
CH455_SCL = 0;
DelayUs(I2C_DELAY);
for(i = 0; i < 8; i++) //读8位数据
{
CH455_SCL = 1;
DelayUs(I2C_DELAY);
bytedata <<= 1;
DelayUs(I2C_DELAY);
bytedata |= (CH455_SDA_IN);
DelayUs(I2C_DELAY);
CH455_SCL = 0;
DelayUs(I2C_DELAY);
}
CH455_SDA_D_OUT; //数据线设置回输出模式
CH455_SDA = high; //SDA=1;
DelayUs(I2C_DELAY);
CH455_SCL = high; //SCL=1;
DelayUs(I2C_DELAY);
CH455_SCL = low; //SCL=0;
DelayUs(I2C_DELAY);
return(bytedata);//返回数据
}
void CH455_Write( UINT16 cmd ) //写命令
{
CH455_I2c_Start(); //启动总线
CH455_I2c_WrByte(((UINT8)(cmd>>7)&CH455_I2C_MASK)|CH455_I2C_ADDR);
CH455_I2c_WrByte((UINT8)cmd); //发送数据
CH455_I2c_Stop(); //结束总线
}
UINT8 CH455_Read( void ) //读取按键
{
UINT8 keycode;
CH455_I2c_Start(); //启动总线
CH455_I2c_WrByte((UINT8)(CH455_GET_KEY>>7)&CH455_I2C_MASK|0x01|CH455_I2C_ADDR);
keycode=CH455_I2c_RdByte(); //读取数据
CH455_I2c_Stop(); //结束总线
return keycode;
}
//单片机头文件
#include "stm32f10x.h"
//
#include "delay.h"
#include "usart.h"
#include "timer.h"
#include "exti.h"
//硬件驱动
#include "Oled_IIC.h"
#include "sim800.h"
#include "ch455.h"
#include "led.h"
//C库
#include
//全局变量
unsigned char usart1Len = 0; //usart1接收的数据长度
unsigned char usart1Buf[64]; //usart1接收缓存
unsigned char usart2Len = 0; //usart2接收的数据长度
unsigned char usart2Buf[64]; //usart2接收缓存
int main(void)
{
unsigned char i,j;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断控制器分组设置
Delay_Init(); //Systick初始化,用于普通的延时
OLED_Init();
CH455_Init();
UsartPrintf(USART1, "\r\nJiangXiaowei Design 2018-07-08 1358801713x\r\n"); //串口1打印
OLED_P8x16Str(0,0,"2018-07-08");
OLED_P8x16Str(0,2,"CH455 Test");
while(1)
{
CH455_Write( CH455_SYSON ); //抗干扰,定时刷新CH455寄存器
CH455_Write( CH455_DIG0 | 0XFF );
switch((CH455_Read()/8)%8)
{
case 0:OLED_P8x16Str(0,4,"0x00 Stop ");break;
case 1:OLED_P8x16Str(0,4,"0x01 Head Up ");break;
case 2:OLED_P8x16Str(0,4,"0x02 Head Down ");break;
case 3:OLED_P8x16Str(0,4,"0x03 Foot Up ");break;
case 4:OLED_P8x16Str(0,4,"0x04 Head Down ");break;
case 5:OLED_P8x16Str(0,4,"0x05 Both Up ");break;
case 6:OLED_P8x16Str(0,4,"0x00 Both Down ");break;
default:;//OLED_P8x16Str(0,6,usart2Buf);
}
}
}