current_v/Src/ht16k33_led_i2c.c
2025-12-31 08:21:43 +08:00

482 lines
12 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file ht16k33_led_i2c.c
* @author Motor Control SDK Team, Yuwell Software XiangenWang
* @brief Voice Recognition Module Initialization Section,
including peripheral initialization and message node insertion, etc.
* @version 1.0
* @changelog version 1.0 初始版本 2025.12.17
- 新增:新建第一个版本的软件,待完善解析命令后的程序执行部分
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2025 Yuwell Software Danyang.Jiangsu.China.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of Yuwell Software nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for Yuwell Software.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY Yuwell Software AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL Yuwell Software OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* USER CODE END Header */
#include "ht16k33_dot_matrix.h"
#define SDA_SET HT16K33_SDA_SET
#define SCL_SET HT16K33_SCL_SET
#define SDA_CLEAR HT16K33_SDA_CLEAR
#define SCL_CLEAR HT16K33_SCL_CLEAR
/* 八行显示内存 */
uint8_t ht16k33_disp_buff[DISP_BUFFER_SIZE];
/**
* @brief 微秒延时
* @param us 需要延时的微秒数
* @retval NONE
* @note 根据MCU主频调整确保时序满足HT16K33要求
* @author jarvis
* @data 2025.11.25
*/
void I2C_Delay_us(uint32_t us)
{
FL_DelayUs(us);
}
/**
* @brief I2C起始条件SCL高电平时SDA从高变低
* @param NONE
* @retval NONE
* @note 根据飞利浦I2C官方文档编写
* @author jarvis
* @data 2025.11.25
*/
void I2C_Start(void)
{
SDA_SET();
SCL_SET();
I2C_Delay_us(1);
SDA_CLEAR();
I2C_Delay_us(1);
SCL_CLEAR();
}
/**
* @brief I2C停止条件SCL高电平时SDA从低变高
* @param NONE
* @retval NONE
* @note 根据飞利浦I2C官方文档编写停止后释放I2C总线控制权
* @author jarvis
* @date 2025.11.25
*/
static void I2C_Stop(void)
{
SDA_CLEAR();
SCL_SET();
I2C_Delay_us(1);
SDA_SET();
I2C_Delay_us(1);
}
/**
* @brief I2C接收应答信号
* @param NONE
* @retval uint8_t - 应答检测结果0表示接收到应答(ACK)1表示未接收到应答(NACK)
* @note SDA引脚需配置为输入模式通过检测PC11引脚电平判断应答状态遵循I2C协议时序
* @author jarvis
* @date 2025.11.25
*/
static uint8_t I2C_ReceiveAck(void)
{
uint8_t ack = 1;
SCL_CLEAR();
SDA_SET(); // 释放SDA总线
I2C_Delay_us(1);
SCL_SET();
I2C_Delay_us(1);
if((FL_GPIO_ReadInputPort(HT16K33_SDA_GPIO_GROUP)&HT16K33_SDA_GPIO_PIN) == 0)
{
ack = 0; // 检测到应答
}
SCL_CLEAR();
return ack;
}
/**
* @brief I2C发送一个字节数据
* @param data - 待发送的8位数据
* @retval NONE
* @note 高位先行(MSB first)遵循I2C协议时序SCL高电平时数据有效
* @author jarvis
* @date 2025.11.25
*/
static void I2C_SendByte(uint8_t data)
{
uint8_t i;
SCL_CLEAR();
for(i = 0; i < 8; i++)
{
if(data & 0x80)
{
SDA_SET(); // 发送最高位
}else{
SDA_CLEAR();
}
data <<= 1;
I2C_Delay_us(1);
SCL_SET();
I2C_Delay_us(1);
SCL_CLEAR();
}
}
/**
* @brief 将显存数据下发到HT16K33驱动的屏幕
* @param disp_buffer - 显存数据缓冲区指针,存储待显示的字节数据
* @retval uint8_t - 发送结果0表示发送成功1表示发送失败(未收到应答)
* @note 采用I2C页写模式地址自动递增需提前定义HT16K33_ADDR(设备地址)、HT16K33_CMD_DISP_ADDR(显示起始地址)、DISP_BUFFER_SIZE(显存大小)
* @author jarvis
* @date 2025.11.25
*/
uint8_t ht16k33_send_buffer(uint8_t* disp_buffer)
{
uint8_t i;
// 1.发送起始信号
I2C_Start();
// 2.发送下位机地址
I2C_SendByte(HT16K33_ADDR);
// 3.接受应答信号
if(I2C_ReceiveAck() != 0)
{
I2C_Stop();
return 1;
}
// 4.发送地址数据
I2C_SendByte(HT16K33_CMD_DISP_ADDR); // 起始地址0x00自动递增
// 5.接受应答信号
if(I2C_ReceiveAck() != 0)
{
I2C_Stop();
return 1;
}
// 6.发送页写数据与接受应答信号
for(i = 0; i < DISP_BUFFER_SIZE; i++)
{
I2C_SendByte(disp_buffer[i]);
I2C_ReceiveAck();
}
// 7.发送停止信号
I2C_Stop();
return 0;
}
/**
* @brief 下发显示使能指令
* @param NONE
* @retval NONE
* @note NONE
* @author jarvis
* @date 2025.11.25
*/
static void ht16k33_chip_disp_enable(void)
{
// 发送显示使能命令(不闪烁)
I2C_Start();
I2C_SendByte(HT16K33_ADDR);
if(I2C_ReceiveAck() != 0)
{
I2C_Stop();
}
I2C_SendByte(HT16K33_CMD_DISPLAY_ON);
if(I2C_ReceiveAck() != 0)
{
I2C_Stop();
}
I2C_Stop();
FL_DelayMs(1);
}
/**
* @brief 初始化芯片
* @param NONE
* @retval NONE
* @note NONE
* @author jarvis
* @date 2025.11.25
*/
void ht16k33_chip_init(void)
{
// 释放总线
SDA_SET();
SCL_SET();
FL_DelayMs(1); // 上电后等待复位完成至少1ms
// 1. 发送系统时钟使能命令
I2C_Start();
I2C_SendByte(HT16K33_ADDR); // 从机地址+写操作
if(I2C_ReceiveAck() != 0)
{
I2C_Stop();
}
I2C_SendByte(HT16K33_CMD_SYSTEM_ON);
if(I2C_ReceiveAck() != 0)
{
I2C_Stop();
}
I2C_Stop();
FL_DelayMs(1);
// 3. 发送最大亮度命令
I2C_Start();
I2C_SendByte(HT16K33_ADDR);
if(I2C_ReceiveAck() != 0)
{
I2C_Stop();
}
I2C_SendByte(HT16K33_CMD_DIMMING_MAX);
if(I2C_ReceiveAck() != 0)
{
I2C_Stop();
}
I2C_Stop();
FL_DelayMs(1);
}
/**
* @brief 根据UI配置信息刷新HT16K33显存缓冲区
* @param ui - UIElements类型的UI配置结构体包含显示模式、数值、指示灯状态等信息
* @retval uint8_t - 刷新结果0表示刷新成功
* @note 1. 支持累时模式(DISPLAY_MODE_TIMER)、氧浓度模式(DISPLAY_MODE_OXYGEN)、错误模式(DISPLAY_MODE_ERROR)三种显示模式
* 2. 氧浓度值范围限制为0-999对应显示0.0%-99.9%累时数值范围限制为0-19999
* 3. 包含断码表SEG_TAB支持0-9数字、'-'、空格、'E'、'L'、'P'、'H'字符显示
* 4. 控制OK灯、报警灯、清洁滤网提示、更换过滤盒提示的显示状态
* 5. 刷新显存后自动调用ht16k33_send_buffer函数下发数据到屏幕
* @author jarvis
* @date 2025.11.25
*/
static void ht16k33_refresh_disp(UIElements ui)
{
// uint8_t o2_hund, o2_ten, o2_unit; // 百位、十位、个位
// uint8_t wh_ten_thou, wh_thou, wh_hund, wh_ten, wh_unit; // 万位、千位、百位、十位、个位
// 定义断码表共阴极7段数码管
uint8_t SEG_TAB[SEG_TABLE_SIZE] =
{
//--0--,--1--,--2--,--3--,--4--,--5--,--6--,--7--,--8--,--9--,
0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,
//'-', ' ', 'E', 'L', 'P', 'H', 'C', 'F', 'U', 'A',
0x40, 0x00, 0x79, 0x38, 0x73, 0x76, 0x39, 0x71, 0x3E, 0x77,
};
// 0.断码表检查并赋值
ui.disp_info.seg_index.first_8_index = (ui.disp_info.seg_index.first_8_index >= SEG_TABLE_SIZE)?(SEG_TABLE_SIZE-1):ui.disp_info.seg_index.first_8_index;
ui.disp_info.seg_index.second_8_index = (ui.disp_info.seg_index.second_8_index >= SEG_TABLE_SIZE)?(SEG_TABLE_SIZE-1):ui.disp_info.seg_index.second_8_index;
ui.disp_info.seg_index.third_8_index = (ui.disp_info.seg_index.third_8_index >= SEG_TABLE_SIZE)?(SEG_TABLE_SIZE-1):ui.disp_info.seg_index.third_8_index;
ui.disp_info.seg_index.fourth_8_index = (ui.disp_info.seg_index.fourth_8_index >= SEG_TABLE_SIZE)?(SEG_TABLE_SIZE-1):ui.disp_info.seg_index.fourth_8_index;
ht16k33_disp_buff[6] = SEG_TAB[ui.disp_info.seg_index.first_8_index];
ht16k33_disp_buff[4] = SEG_TAB[ui.disp_info.seg_index.second_8_index];
ht16k33_disp_buff[2] = SEG_TAB[ui.disp_info.seg_index.third_8_index];
ht16k33_disp_buff[0] = SEG_TAB[ui.disp_info.seg_index.fourth_8_index];
// 1.OK灯显示状态处理
if(ui.ok_led_show == 1)
{
ht16k33_disp_buff[12] |= 0x03;
}else{
ht16k33_disp_buff[12] &= ~(0x03);
}
// 2.报警暂停等状态处理
if(ui.alarm_led_show == 1)
{
ht16k33_disp_buff[12] |= 0x0C;
}else{
ht16k33_disp_buff[12] &= ~(0x0C);
}
// 3.清洁滤网 100h清洁一次
if(ui.clean_filter_show == 1)
{
ht16k33_disp_buff[6] |= 0x80;
ht16k33_disp_buff[4] |= 0x80;
ht16k33_disp_buff[7] |= 0x07;
ht16k33_disp_buff[5] |= 0x07;
}else{
ht16k33_disp_buff[6] &= ~ 0x80;
ht16k33_disp_buff[4] &= ~ 0x80;
ht16k33_disp_buff[7] &= ~ 0x07;
ht16k33_disp_buff[5] &= ~0x07;
}
// 4.更换过滤盒 10000h更换过滤盒
if(ui.replace_box_show == 1)
{
ht16k33_disp_buff[2] |= 0x80;
ht16k33_disp_buff[3] |= 0x07;
}else{
ht16k33_disp_buff[2] &= ~ 0x80;
ht16k33_disp_buff[3] &= ~ 0x07;
}
// 5.累时中文字符
if(ui.total_time_chn == 1)
{
ht16k33_disp_buff[12] |= 0xF0; // “累时”显示
ht16k33_disp_buff[13] |= 0x03;
ht16k33_disp_buff[1] |= 0x01; // “h”显示
}else{
ht16k33_disp_buff[12] &= ~ 0xF0;// “累时”不显示
ht16k33_disp_buff[13] &= ~ 0x03;
ht16k33_disp_buff[1] &= ~ 0x01; // “h”不显示
}
// 6.氧浓度中文字符
if(ui.oxg_concentration_chn == 1)
{
ht16k33_disp_buff[10] |= 0xFF; // “氧浓度”显示
ht16k33_disp_buff[1] |= 0x06; //“%”显示
ht16k33_disp_buff[0] |= 0x80; // “.”显示
}else{
ht16k33_disp_buff[10] &= ~ 0xFF; // “氧浓度”不显示
ht16k33_disp_buff[1] &= ~ 0x06; //“%”不显示
ht16k33_disp_buff[0] &= ~ 0x80; // “.”不显示
}
// 7.最左侧的数字一是否显示
if(ui.disp_info.seg_index.num1_is_show == 1)
{
ht16k33_disp_buff[11] |= 0x03;
}else{
ht16k33_disp_buff[11] &=~ 0x03;
}
ht16k33_send_buffer(ht16k33_disp_buff);
}
/**
* @brief HT16K33屏幕初始化与刷新函数
* @param NONE
* @retval NONE
* @note 1. 函数执行流程释放I2C总线→系统时钟使能→显示使能→设置最大亮度→刷新显示内容
* 2. 上电后等待1ms确保芯片复位完成每步I2C操作后有1ms延时保证稳定性
* 3. 涉及的HT16K33命令宏需提前定义HT16K33_CMD_SYSTEM_ON(系统使能)、HT16K33_CMD_DISPLAY_ON(显示使能)、HT16K33_CMD_DIMMING_MAX(最大亮度)
* 4. 内部调用ht16k33_refresh_disp函数刷新显示内容依赖全局变量ui的配置信息
* 5. 该函数已弃用,建议使用任务与队列形式进行内容刷新
* @author jarvis
* @date 2025.11.25
*/
void ht16k33_refresh_screen(void)
{
ht16k33_chip_init(); // 初始化芯片配置最大亮度
ht16k33_chip_disp_enable();
ht16k33_refresh_disp(ui); // 根据ui变量中的值刷新屏幕
}
/************************ (C) COPYRIGHT YUWELL *****END OF FILE****/