本帖最后由 yang8555u 于 2022-8-29 02:24 编辑
这阵子由于出差,帖子更新不及时,请见谅。
本期帖子,介绍的是TM1638数码管的经典应用,做一个小型的计数器。TM1638是天马微电子推出的一款芯片,主要用于矩阵键盘、数码管、多路LED灯等应用,在日常生活中应用非常普遍。
根据芯片手册,我使用普通GPIO模拟的方式,驱动TM1638。
代码如下:
TM1638.h
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2022-08-06 11618 the first version
*/
#ifndef APPLICATIONS_TM1638_H_
#define APPLICATIONS_TM1638_H_
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <stdint.h>
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 2048
#define THREAD_TIMESLICE 5
static rt_thread_t tid1 = RT_NULL;
#define DATA_COMMAND 0X40
#define DISP_COMMAND 0x80
#define ADDR_COMMAND 0XC0
#define TM1638_DIO GET_PIN(B, 10)
#define TM1638_CLK GET_PIN(E, 13)
#define TM1638_CS GET_PIN(B, 12)
//#define TM1638_CLK_ENABLE()
#define TM1638_DIO_SET() rt_pin_write(TM1638_DIO, PIN_HIGH)
#define TM1638_DIO_RESET() rt_pin_write(TM1638_DIO, PIN_LOW)
#define TM1638_DIO_READ() rt_pin_read(TM1638_DIO)
#define TM1638_CLK_SET() rt_pin_write(TM1638_CLK, PIN_HIGH)
#define TM1638_CLK_RESET() rt_pin_write(TM1638_CLK, PIN_LOW)
#define TM1638_CS_SET() rt_pin_write(TM1638_CS, PIN_HIGH)
#define TM1638_CS_RESET() rt_pin_write(TM1638_CS, PIN_LOW)
void TM1638_init(void);//TM1638初始化函数
void TM1638_Write(unsigned char DATA); //写数据函数
unsigned char TM1638_Read(void) ; //读数据函数
void Write_COM(unsigned char cmd); //发送命令字
void Write_DATA(unsigned char add,unsigned char DATA); //指定地址写入数据,按地址单独点亮数码内容
void Write_allLED(unsigned char LED_flag); //控制全部LED函数,LED_flag表示各个LED状态
unsigned char Read_key(void);//读取按键值
#endif /* APPLICATIONS_TM1638_H_ */
TM1638.c
#include <tm1638.h>
#include <rtthread.h>
#include <rtdevice.h>
#include "n32g45x_rcc.h"
void TM1638_init(void)
{
unsigned char i;
/*CLK ENABLE*/
/*GPIO MODE*/
rt_pin_mode(TM1638_DIO,PIN_MODE_OUTPUT_OD);
rt_pin_mode(TM1638_CLK,PIN_MODE_OUTPUT);
rt_pin_mode(TM1638_CS,PIN_MODE_OUTPUT);
Write_COM(0x89); //亮度 (0x88-0x8f)8级亮度可调
Write_COM(0x40); //采用地址自动加1
TM1638_CS_RESET() ; //
TM1638_Write(0xc0); //设置起始地址
for(i=0;i<16;i++) //传送16个字节的数据
TM1638_Write(0x40);//数码管显示横杠
TM1638_CS_SET() ;
}
void TM1638_Write(unsigned char DATA)
{
unsigned char i;
for(i=0;i<8;i++)
{
TM1638_CLK_RESET() ;
if(DATA&0X01)
TM1638_DIO_SET() ;
else
TM1638_DIO_RESET() ;
DATA>>=1;
TM1638_CLK_SET() ;
}
}
unsigned char TM1638_Read(void)
{
unsigned char i;
unsigned char temp=0;
TM1638_DIO_SET() ;
for(i=0;i<8;i++)
{
temp>>=1;
TM1638_CLK_RESET() ;
TM1638_DIO_SET() ;
if(TM1638_DIO_READ())
temp|=0x80;
TM1638_CLK_SET() ;
}
return temp;
}
void Write_COM(unsigned char cmd)
{
TM1638_CS_RESET() ;
TM1638_Write(cmd);
TM1638_CS_SET() ;
rt_thread_mdelay(1);
}
unsigned char Read_key(void)
{
unsigned char c[4],i;
unsigned char key_value=0;
TM1638_CS_RESET() ;
TM1638_Write(0x42);
rt_thread_mdelay(5);
for(i=0;i<4;i++)
c=TM1638_DIO_READ();
TM1638_CS_SET() ;
//K1
if(c[0]==0x04) key_value=1;
if(c[0]==0x40) key_value=2;
if(c[1]==0x04) key_value=3;
if(c[1]==0x40) key_value=4;
if(c[2]==0x04) key_value=5;
if(c[2]==0x40) key_value=6;
if(c[3]==0x04) key_value=7;
if(c[3]==0x40) key_value=8;
//K2
if(c[0]==0x02) key_value=9;
if(c[0]==0x20) key_value=10;
if(c[1]==0x02) key_value=11;
if(c[1]==0x20) key_value=12;
if(c[2]==0x02) key_value=13;
if(c[2]==0x20) key_value=14;
if(c[3]==0x02) key_value=15;
if(c[3]==0x20) key_value=16;
//K3
if(c[0]==0x01) key_value=17;
if(c[0]==0x10) key_value=18;
if(c[1]==0x01) key_value=19;
if(c[1]==0x10) key_value=20;
if(c[2]==0x01) key_value=21;
if(c[2]==0x10) key_value=22;
if(c[3]==0x01) key_value=23;
if(c[3]==0x10) key_value=24;
return key_value;
}
void Write_DATA(unsigned char add,unsigned char DATA)
{
Write_COM(0x44);
TM1638_CS_RESET() ;
TM1638_Write(0xc0|add);
TM1638_Write(DATA);
TM1638_CS_SET() ;
}
void Write_allLED(unsigned char LED_flag)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(LED_flag&(1<<i))
//Write_DATA(2*i+1,3);
Write_DATA(2*i+1,1);
else
Write_DATA(2*i+1,0);
}
}
void show_data(uint32_t i)
{
unsigned char shumaguan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
// 0 1 2 3 4 5 6 7
0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
// 8 9 A B C D E F
0xff };
Write_DATA(0x0,shumaguan[i/ 10000000 % 10]);
Write_DATA(0x2,shumaguan[i/ 1000000 % 10]);
Write_DATA(0x4,shumaguan[i/ 100000 % 10]);
Write_DATA(0x6,shumaguan[i/ 10000 % 10]);
Write_DATA(0x8,shumaguan[i/ 1000 % 10]);
Write_DATA(0xa,shumaguan[i/ 100 % 10]);
Write_DATA(0xc,shumaguan[i/ 10 % 10]);
Write_DATA(0xe,shumaguan[i % 10]);
}
static void tm1638_collect_thread_entry(void *parameter)
{
TM1638_init();
uint32_t i=12345678;
while(i++)
{
show_data(i);
rt_thread_mdelay(100);
}
}
int tm1638_send(void)
{
/* 创建线程*/
tid1 = rt_thread_create("tm1638_collect_thread", tm1638_collect_thread_entry, RT_NULL, THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
return 0;
}
MSH_CMD_EXPORT(tm1638_send,test)
由代码可见,我们使用gpio模拟的方式,驱动tm1638,并形成一个每0.1秒计数一次的计数器应用。程序下载后,在串口控制台,可以输入tm1638_send,启动tm1638线程,并运行计数器应用。
视频如下:
NS1
在前面帖子中,有介绍I2C读取温湿度传感器,所以我们可以将其整合起来,便可以使用数码管显示N32WB452板载的温湿度传感器的数据,模拟真实应用场景。
改动代码如下:
//增加show_data函数,用于显示温湿度数据。
void hdc2010_get_data()
{
read_regs(i2c_bus, HDC2010_TEMPERATURE_LOW, temperature_reg);
temperature_raw = temperature_reg[0] + temperature_reg[1] * 256;
temperature = (double) temperature_raw / 65536;
temperature = temperature * 165 - 40;
read_regs(i2c_bus, HDC2010_HUMIDITY_LOW, humidity_reg);
humidity_raw = humidity_reg[0] + humidity_reg[1] * 256;
humidity = (double) humidity_raw / 65536*100;
LOG_I("temperature = %d.%d,humidity = %d.%d\n", (int )temperature, (int )(temperature * 10) % 10,(int )humidity, (int )(humidity * 10) % 10);
show_data(temperature * 10,humidity*10);
}
//改造原来的show_data函数,并增加小数点显示。
void show_data(uint32_t i,uint32_t s)
{
unsigned char shumaguan[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,
// 0 1 2 3 4 5 6 7
0x7f,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
// 8 9 A B C D E F
0xff };
unsigned char shumaguandian[]={0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,
// 0 1 2 3 4 5 6 7
0xFF,0xEF};
// 8 9
Write_DATA(0x0,shumaguan[i/ 100 % 10]);
Write_DATA(0x2,shumaguandian[i/ 10 % 10]);
Write_DATA(0x4,shumaguan[i % 10]);
Write_DATA(0x6,0x40);
Write_DATA(0x8,shumaguandian[s/ 100 % 10]);
Write_DATA(0xa,shumaguandian[s/ 10 % 10]);
Write_DATA(0xc,shumaguandian[s % 10]);
Write_DATA(0xe,0x40);
}
温湿度显示如下:
NS2