一、说明
勇士开发板上有一个四位共阴数码管,于是想着能用它来显示点什么,想了一下,也没什么可以显示的,只好用它来做个计时器,因为只有四位,也不可能显示很复杂的内容。
四位数码管如果同时显示分钟和秒中,正好可以用前两位显示分钟,后两位显示秒中,那么可以最大显示99分钟59秒。想好了就开始干。
二、方案设计
1、查看原理图
从原理图可以看出,开发板使用了一颗I2C接口的数码管驱动芯片TM1650,驱动芯片与DSP之间只需要两个IO口就可以实现数码管的控制,还是非常方便的。
另外,该芯片通过读的方式能够检测外部的按键。
2、TM1650介绍
TM1650是一款国产4位共阴数码管驱动芯片,它还带有矩阵按键扫码功能。它的基本参数如下:
- 工作电压:3~5V
- 数码管驱动模式:8段x4位共阴数码管
- 矩阵按键驱动模式:7x4矩阵按键,不支持组合键
- 通信接口:类IIC,使用了IIC相同的时序,但没有完全遵守IIC的协议,不带从机地址
引脚定义
SCL:串行通信时钟线
SDA:串行通信数据线
做数码管驱动使用时
TM1650使用的是类IIC接口,只是不带从机地址机制。所以总线上的基本信号也包含起始信号,ACK应答,结束信号,同时字节数据发送时,也是按照标准IIC的MSB First顺序。
发送命令设置数码管显示工作参数
通信格式:起始信号,模式命令(1字节),显示命令(1字节),结束信号
这个指令用于设置数码管显示的相关参数。例如亮度,7段或者8段显示,显示的开关。模式命令固定为0x48,而显示命令则满足以下格式:
3、设计思路
计时:因为勇士027系列dsp没有硬件RTC模块,所以只能使用硬件定时器来实现。使用cputimer0来设置1ms的周期中断,在中断里面进行计数,计数到1s后进行更新数码管显示。
暂停功能:利用按键s101来实现计数的暂停与继续。
亮度调节功能:利用按键s102来实现数码管亮度的调节
计数复位功能:利用按键s103来实现计数值的复位,从零开始计时
三、代码编写
main.c
#include "dsc_config.h"
#include <syscalls.h>
#include "IQmathLib.h"
#include "sci.h"
#include "TM1650_IIC.h"
#include <stdio.h>
extern void InitKEY(void);
extern void InitLED(void);
void test(void);
Uint16 sec_rtc = 0;
Uint16 min_rtc = 0;
char keyReg = 0;
extern Uint32 msec_cnt;
extern volatile Uint8 msec_cnt_on;
int main(void)
{
uint16_t cnt = 0;
InitSysCtrl();
InitFlash();
InitSciGpio();
DINT;
InitPieCtrl();
IER = 0x0000;
IFR = 0x0000;
InitPieVectTable();
Scia_Config(9600);
Timer0_init();
InitI2C_Gpio();
I2CA_Init();
softResetIIC_BUS();
LigntVal = 0x11;
TM1650_Send(CMD_SEG, LigntVal);
TM1650_Send(DIG0, SEG7Table[0]);
TM1650_Send(DIG1, SEG7Table[0]);
TM1650_Send(DIG2, SEG7Table[0]);
TM1650_Send(DIG3, SEG7Table[0]);
EINT;
InitKEY();
InitLED();
Scia_Print("Hello haawking!\r\n");
while(1)
{
if((CpuTimer0.InterruptCount % 250) == 0)
{
TM1650_Read(CMD_KEY, &keyVal);
if(keyVal == 0x44)
{
msec_cnt_on ^= 0x01;
uart_printf("msec_cnt_on = %d\r\n",msec_cnt_on);
}
if(keyVal == 0x4c)
{
LigntVal = (LigntVal + 0x20) & 0x7F;
TM1650_Send(CMD_SEG, LigntVal);
uart_printf("LigntVal = %d\r\n",LigntVal);
}
if(keyVal == 0x54)
{
msec_cnt = 0;
sec_rtc = 0;
min_rtc = 0;
keyReg = 0;
TM1650_Send(DIG0,SEG7Table[0]);
TM1650_Send(DIG1, SEG7Table[0]);
TM1650_Send(DIG2, SEG7Table[0]);
TM1650_Send(DIG3, SEG7Table[0]);
GpioDataRegs.GPATOGGLE.bit.GPIO7 = 1;
uart_printf("cnt reset\r\n");
}
}
if(msec_cnt >= 1000)
{
msec_cnt = 0;
GpioDataRegs.GPATOGGLE.bit.GPIO6 = 1;
sec_rtc++;
if(sec_rtc >= 60)
{
sec_rtc = 0;
min_rtc++;
if(min_rtc >= 100)
{
min_rtc = 99;
sec_rtc = 59;
}
}
TM1650_Send(DIG0,SEG7Table[min_rtc / 10]);
TM1650_Send(DIG1, SEG7Table[min_rtc % 10]);
TM1650_Send(DIG2, SEG7Table[sec_rtc / 10]);
TM1650_Send(DIG3, SEG7Table[sec_rtc % 10]);
}
}
return 0;
}
timer.c
/******************************************************************
文 档 名: epwm.c
D S P: DSC28027
使 用 库:
作 用:
说 明: 提供timer接口初始化配置
---------------------------- 使用说明 ----------------------------
功能描述:
版 本:V0.0.3
时 间:2022年1月19日
作 者:
@ mail:support@mail.haawking.com
******************************************************************/
#include "dsc_config.h"
#include "TM1650_IIC.h"
#include "timer.h"
timer0 timer0Base;
volatile uint32_t Tick;
Uint32 msec_cnt = 0;//用于计秒
volatile Uint8 msec_cnt_on = 0;//0-on,1-off
/******************************************************************
*函数名:Timer0_init
*参 数:无
*返回值:无
*作 用:初始化Timer
******************************************************************/
void Timer0_init()
{
/*初始化Cpu定时器*/
InitCpuTimers();
/*开启模块中断使能,位于 Timer->RegsAddr->TCR.bit.TIE = 1;
120MHz,1000us ,即为 1ms中断周期*/
ConfigCpuTimer(&CpuTimer0, 120, 1000);
/* 使能中断*/
CpuTimer0Regs.TCR.bit.TIE = 1;
/* 开始计时*/
CpuTimer0Regs.TCR.bit.TSS = 0;
/*重映射中断服务函数*/
EALLOW;
PieVectTable.TINT0 = &cpu_timer0_isr;
EDIS;
/*连接CPU中断Y*/
IER |= M_INT1;
/*连接Y中断里的第几位*/
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;
}
/******************************************************************
*函数名:INTERRUPT void cpu_timer0_isr(void)
*参 数:无
*返回值:无
*作 用:CPU 定时器0 中断服务函数
******************************************************************/
INTERRUPT void cpu_timer0_isr(void)
{
#if 0
timer0Base.msCounter++;
timer0Base.Mark_Para.Status_Bits.OnemsdFlag = 1;
Tick++;
/*中断响应*/
EALLOW;
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
EDIS;
#endif
/*定时器0中断次数累计*/
CpuTimer0.InterruptCount++;
if(msec_cnt_on == 0)
{
msec_cnt++;
}
/*检测IIC模块状态为空闲还是写入*/
char i;
for(i = 0; i < IIC_NODE_NUM; i++)
{
PtrMsg[i]->IIC_TimerOUT = (PtrMsg[i]->MasterStatus == IIC_IDLE) ? 0 : (PtrMsg[i]->IIC_TimerOUT + 1);
}
/*通知可以接收第一组中断的所有中断*/
PieCtrlRegs.PIEACK.all = PIEACK_GROUP1;
}