目录
本专辑最终会以“wifi版温湿度蓝牙网关项目”结案,敬请关注、订阅、收藏
文章内容
基于sample_project示例创建一个空工程,实现与TM1640通信,点亮LED数码管。
硬件
-
一款 ESP32 开发板(本专辑中均使用ESP32-LyraT-Mini V1.2开发板)
-
USB 数据线 (A 转 Micro-B)
-
电脑(Windows)
-
在开发板上人为增加TM1640显示模块
TM1640介绍
TM1640 是一种LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 驱动等电路。显示模式为8段×16位,主要应用于电子产品LED显示屏驱动。
微处理器的数据通过两线总线接口和 TM1640 通信,在输入数据时当 CLK 是高电平时,DIN 上的信号必须保持不变;只有 CLK 上的时钟信号为低电平时,DIN 上的信号才能改变。数据的输入总是低位在前,高位在后传输.数据输入的开始条件是 CLK 为高电平时,DIN 由高变低;结束条件是 CLK 为高时,DIN 由低电平变为高电平。
指令数据传输过程如下图:
写 SRAM 数据地址自动加 1 模式:
写 SRAM 数据固定地址模式:
ESP32需要通过软件模拟的方式实现两线总线接口与TM1640通信。
TM1640模块介绍
本实验使用的显示模块为之前的自有项目模块,使用的是共阴极数码管。
4位共阴极数码管电路原理图如下图所示。
3位共阴极数码管电路原理图如下图所示。
当前模块使用TM1640连接3个数码管,SEG并接3个数码管的段位,GRID按照顺序连接数码管的DIG位。
根据TM1640的"显示数据、地址、芯片管脚之间的对应关系"可确定4位段码管显存地址起始为0xC0H,3位段码管显存地址起始分别0xC4H和0xC7H。
当要点亮某段位时对应SEG写入1,熄灭某段位时对应SEG写入0。段码编码如下图所示。
基于sample_project示例创建工程
ctrl+alt+P,输入ESP-IDF show,选择“ESP-IDF: Show Examples Projects” ,找到“sample_project”,选择“Create Project using example sample_project”,在跳出的保存框中,选择某一文件夹,新建Project文件夹,保存。用于存放新建的sample_project工程。
注意:文件夹名称和路径中最好不要有中文且路径尽量短;
编写程序
1)新建两线总线驱动文件夹
在项目文件夹下新建"components"文件夹,"soft_2wire_master"子文件夹。子文件夹中新建4个文件"CMakeLists.txt"、"linker.lf"、"soft_2wire_master.c"、"soft_2wire_master.h"。
单击打开新建的"CMakeLists.txt"文件,填充内容:
idf_component_register(SRCS "soft_2wire_master.c"
INCLUDE_DIRS "."
PRIV_REQUIRES driver
LDFRAGMENTS linker.lf)
单击打开新建的"linker.lf"文件,填充内容:
[mapping:main_default]
archive: libsoft_i2c_master.a
entries:
* (noflash)
打开"main"文件夹下的"CMakeLists.txt",添加如下内容:
2)编写soft_2wire_master.h文件
/*
* SPDX-FileCopyrightText: 2010-2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: CC0-1.0
*/
#pragma once
#include <stdint.h>
#include "esp_err.h"
//#include "soc/gpio_num.h"
#ifdef __cplusplus
extern "C" {
#endif
void InitLED(void); //初始化TM1640
void ClearAllShow(void);//清屏(3个数码屏均不显示)
void ClearShow(uint8_t ledindex);//选择指定数码屏清屏
void ShowMearData(uint8_t ledindex,uint16_t datavalue);//选择指定数码屏显示数据
#ifdef __cplusplus
}
#endif
3)编写soft_2wire_master.c文件
添加头文件:
#include "freertos/FreeRTOS.h" //所有文件基本都要包含,数据类型定义
#include "esp_rom_sys.h" //需要用us延迟函数
#include "driver/gpio.h" //对管脚进行相关定义
#include "soft_2wire_master.h"
定义管脚名称并绑定管脚号:
//GPIO管脚号
#define DIO 12
#define CLK 13
用宏定义定义3个数码管的显存起始地址、显示长度、小数点位数,为程序中指定某数码管做准备(可以用结构体数组,当前案例用的数组实现的)。
定义编码数组,用于存放数字编码。数字0对应数组索引0位,数字1对应数组索引1位,以此类体。
//显示内容正好对应0123456789abcdef
uint8_t typeTable[] = {
0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c,
0x39, 0x5e, 0x79, 0x71
};
编写起始、结束、发送数据的函数。
//TM1640数据的输入总是低位在前,高位在后传输.在输入数据时当 CLK 是高电平时,DIN 上的信号必须保持不变
void Send(uint8_t bytedata)
{
for (uint8_t i = 0; i <= 7; i++) {
gpio_set_level(CLK,0);
uint8_t bit = (bytedata >> i) & 0x01;
gpio_set_level(DIO,bit);
gpio_set_level(CLK,1);
}
gpio_set_level(CLK,0);
}
//数据输入的开始条件是 CLK 为高电平时,DIN 由高变低
void Start(void)
{
gpio_set_level(DIO,0);
esp_rom_delay_us(5);
}
//结束条件是 CLK 为高时,DIN 由低电平变为高电平
void Stop(void)
{
gpio_set_level(DIO,0);
gpio_set_level(CLK,1);
gpio_set_level(DIO,1);
}
初始化TM1640并清屏
void InitLED(void)
{
gpio_reset_pin(CLK);
gpio_reset_pin(DIO);
gpio_set_direction(CLK, GPIO_MODE_OUTPUT);//sclk配置为输出模式
gpio_set_direction(DIO, GPIO_MODE_OUTPUT);//din配置为只输出模式
gpio_set_pull_mode(CLK, GPIO_PULLUP_ONLY);//线路图有外部上拉的
gpio_set_pull_mode(DIO, GPIO_PULLUP_ONLY);//线路图有外部上拉的
//设置两个管脚为默认为高电平
gpio_set_level(DIO,1);
gpio_set_level(CLK,1);
ClearAllShow();
}
//清屏//可当初始化函数用
void ClearAllShow(void)
{
portENTER_CRITICAL(&g_lock);//进入临界段
Start();
Send(0x40); // 数据命令,写数据到寄存器,自动地址增加,普通模式
Stop();
Start();
Send(0xc0); //地址命令设置,显示地址00H --设置起始地址
for(uint8_t i = 0; i <= 10; i++) {
Send(0x00);
}
Stop();
Start();
Send(0x8f);//显示控制设置,脉冲宽度14/16,显示开
Stop();
portEXIT_CRITICAL(&g_lock);//退出临界段
}
写数据到指定的数码屏
//当前假设3位数码管显示1位小数点数据*10传递,4位数码管显示2位小数点数据*100进行传递
void ShowMearData(uint8_t ledindex,uint16_t datavalue)
{
uint8_t t[maxDigLen];
uint8_t showdataindex=0;
if(ledindex==0)//4位数码管
{
t[0]= datavalue/1000;
t[1]= (datavalue%1000)/100;
t[2]= (datavalue%100)/10;
t[3]= datavalue%10;
}
else
{
t[0]= datavalue/100;
t[1]= (datavalue%100)/10;
t[2]= datavalue%10;
}
portENTER_CRITICAL(&g_lock);//进入临界段
/*Start();
Send(0x40); // 数据命令,写数据到寄存器,自动地址增加,普通模式
Stop();*/
Start();
Send(ledgroupaddr[ledindex]); //地址命令设置,显示地址00H --设置起始地址
for(uint8_t i = 0; i <= ledgrouplen[ledindex]; i++) {
showdataindex = t[i];
//在指定位后面显示小数点
if(i==ledgrouppoint[ledindex])
{
Send(typeTable[showdataindex]|0x80);//该位显示小数点
}
else
{
Send(typeTable[showdataindex]);
}
}
Stop();
Start();
Send(0x8f);//显示控制设置,脉冲宽度14/16,显示开
Stop();
portEXIT_CRITICAL(&g_lock);//退出临界段
}
4)编写main.c文件
#include <stdio.h>
#include "esp_log.h"
#include "soft_2wire_master.h"
const char* EXAMPLE_TAG = "soft_2wire_master";
void app_main(void)
{
InitLED();//初始化LED
ShowMearData(0,(12.34*100));
ShowMearData(1,(56.7*10));
ShowMearData(2,(89.0*10));
while(1)
{
// Add your main loop handling code here.
}
}
编译下载程序
点击左下角编译按钮。成功编译后打开开发板并连接开发板UART烧录口,选择正确的串口号,点击下载,选择UART,下载程序。
🌹欢迎关注、订阅、收藏🌹
文章中有不清晰或者有疑问、错误的地方,请务必留言提醒、讨论。非常感谢!!!
本专辑最终会以“wifi版温湿度蓝牙网关项目”结案,敬请关注、订阅、收藏
欢迎关注并下载源码
文章同步发表于公众号"IT搬砖客",可免费下载源码。
欢迎关注并留言。