本文的主要开发内容是对8位数码管的编程驱动以及实现数码管从10到0的递减显示,首先需要设置数码管与MCU的引脚连接。下图为8位数码管的电路原理图、引脚功能定义,所用到的数码管驱动芯片是HC595,这是一颗高速串行数据转并行输出芯片。

从以上电路原理图知,8位数码管由两片HC595芯片组成,其中第一片HC595芯片负责接收串行数据输入,并将低八位串行数据用于驱动单个数码管,高八位数据串行输入到第二片HC595芯片,用于驱动第几位数码管显示。当低八位数据和高八位串行数据传输完毕,在RCLK引脚上给予不小于2us的上升沿,此时将有一位数码管被点亮。
按照以上说明,那么每次只能点亮一位数码管,这可无法实现多位数码管同时点亮呢。然而非也非也,由于人眼都会存在一个视觉暂留性,在极短的时间内,快速循环点亮多位数码管,那么我们看到的就是多位数码管"同时点亮"了。这个和手机屏幕显示也是类似的,手机屏幕的各个显示点也并非同时点亮,而是以超快的频率循环点亮来实现整个屏幕内容的显示。
一位数码管示意图

数码管模块由八段LED组成,均为共阳极,那么驱动LED显示就需要锁存器中的数据为低电平数据,LED段驱动顺序为a-b-c-d-e-f-g-h,然而对应的HC595内部锁存器是数据存储顺序为LED段驱动顺序的倒序。
例如,数码管驱动显示数字6(小数点不显示),对应LED段驱动数据为01000001,而锁存器存储数据为10000010。对于一位数码管来说,它能够显示的数字范围是0~9,因此可以将0~9的锁存器数据封装在一个数组中,方便数码管显示0~9中任一位数据时直接调用。
根据以上原理,在程序开发中实现了数码管从10到0递减显示,并且额外增加了一个秒表计时器功能,开机默认运行倒计时模式,循环从10递减到0。按下按键1实现功能切换,切换至秒表计时器模式,数码管显示0,按下按键1实现计算功能,理论上可以计时的时间为2^32秒,实际上应该用不了计时这么久的。再一次按下按键实现计时终止,当前数码管显示最终的计时时间,再次按下按键1,实现计时清零重新返回计时启动模式。
无论是倒计时模式还是计时器模式,数码管数字刷新显示操作均由定时器0的中断回调函数完成,而精确延时操作由定时器1完成。定时器中断的机制是定时器在每隔设定的间隔内触发一次中断,中断可以暂停当前CPU的执行任务,转向执行定时器中断回调函数的任务,执行完毕后返回执行上一次CPU暂停执行的任务。因此在程序中需要指定中断优先级别,中断级别是数字越小优先级越高,程序中设定按键中断完成功能模式切换,将按键中断优先级设为最高,其次是定时器1精确延时中断优先级为次高,定时器0数码管刷新中断优先级最低。

syscfg文件下载链接:syscfg.zip
源代码:
#include "ti_msp_dl_config.h"
#include <math.h>
#define NUM_MAXLENGTH 8
#define delay_us 32
typedef struct{
uint32_t Num_start;
uint8_t Num_polarity;
uint8_t polarity_flag;
uint8_t func_mode;//0表示倒计时模式,1表示秒表模式
uint8_t stopwatch_status;//0表示等待启动秒表,1表示正在计时,2表示停止计时
}LED_Segment_Mode;
LED_Segment_Mode LS_Mode;
uint8_t Num_List[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x8C,0xBF,0xC6,0xA1,0x86,0xFF,0xbf};
int32_t Num_Decrease=1;
/**
* @brief 时钟上升沿配置
*
* @param[in] 外设端口PORTx、t1、t2
*
*/
void HC595_CLKRisingEdge_Config(GPIO_Regs* PORTx,uint32_t PINx,uint32_t t1,uint32_t t2){
DL_GPIO_clearPins(PORTx, PINx);
delay_cycles(delay_us*t1);
DL_GPIO_setPins(PORTx, PINx);
delay_cycles(delay_us*t2);
}
/**
* @brief HC595输入1字节数据
*
* @param[in] byte字节数据
*
*/
void LED_Segment_WriteByte(uint8_t byte){
for(uint8_t i=1;i<=8;i++){
if(byte&0x80){
DL_GPIO_setPins(PORT_HC595_PORT,PORT_HC595_PIN_HC595_DIO_PIN);
}
else
{
DL_GPIO_clearPins(PORT_HC595_PORT,PORT_HC595_PIN_HC595_DIO_PIN);
}
HC595_CLKRisingEdge_Config(PORT_HC595_PORT,PORT_HC595_PIN_HC595_SCLK_PIN,2,2);
byte<<=1;
}
}
/**
* @brief 数码管显示一位数字
*
* @param[in] Num_one数字,index显示位置
*
*/
void LED_Segment_Display_Num_One(uint8_t Num_one,uint8_t index){
// switch(Num_one){
// case 0:
// break;
// }
LED_Segment_WriteByte(Num_List[Num_one]);
LED_Segment_WriteByte(1<<index);
HC595_CLKRisingEdge_Config(PORT_HC595_PORT,PORT_HC595_PIN_HC595_RCLK_PIN,2,2);
}
/**
* @brief 数码管显示小数点
*
* @param[in] Num_one小数点,index显示位置
*
*/
void LED_Segment_Display_point(uint8_t Num_one,uint8_t index){
// switch(Num_one){
// case 0:
// break;
// }
LED_Segment_WriteByte(Num_one);
LED_Segment_WriteByte(1<<index);
HC595_CLKRisingEdge_Config(PORT_HC595_PORT,PORT_HC595_PIN_HC595_RCLK_PIN,2,2);
}
/**
* @brief 数码管显示处理
*
* @param[in] Num数字
*
*/
void Num_LED_Segment_Process(uint32_t Num){
uint8_t num_lsb=0;
uint8_t i;
for(i=0;i<NUM_MAXLENGTH;i++)
{
num_lsb=Num%10;
Num/=10;
LED_Segment_Display_Num_One(num_lsb,i);
if(Num==0)break;
}
if(LS_Mode.Num_polarity==0){
LED_Segment_WriteByte(0xbf);
LED_Segment_WriteByte(0x01<<(i+1));
HC595_CLKRisingEdge_Config(PORT_HC595_PORT,PORT_HC595_PIN_HC595_RCLK_PIN,2,2);
}
}
int main(void)
{
SYSCFG_DL_init();
NVIC_SetPriority(TIMER_0_INST_INT_IRQN, 2);
NVIC_EnableIRQ(TIMER_0_INST_INT_IRQN);
DL_TimerG_startCounter(TIMER_0_INST);
//
NVIC_SetPriority(TIMER_1_INST_INT_IRQN, 1);
NVIC_EnableIRQ(TIMER_1_INST_INT_IRQN);
DL_TimerG_startCounter(TIMER_1_INST);
NVIC_SetPriority(GPIO_MULTIPLE_GPIOA_INT_IRQN, 0);
NVIC_EnableIRQ(GPIO_MULTIPLE_GPIOA_INT_IRQN);
LS_Mode.Num_start=10;
LS_Mode.polarity_flag=1;
LS_Mode.Num_polarity=1;//默认显示正数
LS_Mode.func_mode=0;
LS_Mode.stopwatch_status=0;
while (1) {
delay_cycles(10);
// LED_Segment_Display_Num_One(0x7f,0x01<<5);
// LED_Segment_Display_point(0x7f,5);
// Num_LED_Segment_Process_Float(0.356,2);
}
}
void TIMER_0_INST_IRQHandler(void)
{
switch (DL_TimerG_getPendingInterrupt(TIMER_0_INST))
{
case DL_TIMER_IIDX_ZERO:
Num_LED_Segment_Process(Num_Decrease);
break;
default:
break;
}
}
void TIMER_1_INST_IRQHandler(void)
{
switch (DL_TimerG_getPendingInterrupt(TIMER_1_INST)) {
case DL_TIMER_IIDX_ZERO:
// DL_GPIO_togglePins(GPIO_LEDS_PORT,GPIO_LEDS_USER_LED_1_PIN | GPIO_LEDS_USER_TEST_PIN);
if(LS_Mode.func_mode==0){
if(LS_Mode.polarity_flag==1){
Num_Decrease--;
if(Num_Decrease<0)
Num_Decrease=LS_Mode.Num_start;
}
// else
// {
//
// if(LS_Mode.Num_polarity==1){
// Num_Decrease--;
// if(Num_Decrease<0)
// LS_Mode.Num_polarity=0;
// }
// else{
// Num_Decrease++;
// if(Num_Decrease==LS_Mode.Num_start)
// LS_Mode.Num_polarity=1;
// }
// }
}
else
{
if(LS_Mode.stopwatch_status==0)
Num_Decrease=0;
else if(LS_Mode.stopwatch_status==1)
Num_Decrease++;
else
{
}
}
break;
default:
break;
}
}
void GROUP1_IRQHandler(void)
{
switch (DL_GPIO_getPendingInterrupt(PORT_Key2_PORT)) {
case PORT_Key2_PIN_Key2_IIDX:
switch(LS_Mode.stopwatch_status){
case 0:
LS_Mode.stopwatch_status++;
break;
case 1:
LS_Mode.stopwatch_status++;
break;
case 2:
LS_Mode.stopwatch_status=0;
break;
default:
LS_Mode.stopwatch_status=0;
break;
}
break;
case PORT_Key1_PIN_Key1_IIDX:
DL_GPIO_togglePins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
if(LS_Mode.func_mode==0)
{
Num_Decrease=0;
LS_Mode.stopwatch_status=0;
LS_Mode.func_mode++;
}
else if(LS_Mode.func_mode==1)
{
LS_Mode.func_mode--;
Num_Decrease=LS_Mode.Num_start;
}
else
{
LS_Mode.func_mode=0;
Num_Decrease=LS_Mode.Num_start;
}
break;
default:
// DL_GPIO_togglePins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
break;
}
}效果图:


我要赚赏金
