模拟I2C控制TM1650数码管显示电压电流
- 数码管的逻辑
- TM1650 原理
- 模拟I2C的实现
- TM1650驱动
- 电压电流显示
数码管的逻辑
通过数码管来表示字符。
数码管的abcdefg和dp分别对应这发送过去的8位数据位比如0x3F -> 0011 1111 表示0字符。
如果要加上小数点则在最高位加一,变成了 1011 1111。
TM1650 原理
SCL:串行通信时钟线
SDA:串行通信数据线
做数码管驱动使用时
DIGx:数码管的位选引脚,灌电流驱动,最大可吸收150mA电流
A~DP:数码管的段驱动引脚,拉电流驱动,最大可输出25mA电流
这个指令用于设置数码管显示的相关参数。例如亮度,7段或者8段显示,显示的开关。模式命令固定为0x48,而显示命令则满足以下格式:
TM1650内部有4字节的显存,地址分别为0x68,0x6A,0x6C,0x6E,分别用于存放显示在DIG1,DIG2,DIG3,DIG4的段码数据。例如想要让DIG1对应的数码管位显示数字2,则要往0x68单元写入数字2的共阴段码0x5b。
模拟I2C的实现
这边主要参考了Leung_ManWah老哥
static void SDA_OUT_MODE(void);
static void SDA_IN_MODE(void);
void IIC2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStructure.Pin = IIC_SCL_PIN;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStructure.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(IIC_SCL_PORT, &GPIO_InitStructure);
GPIO_InitStructure.Pin = IIC_SDA_PIN;
HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
IIC_Stop();
}
void IIC_Start(void)
{
SDA_OUT_MODE();
IIC_SDA_1();
IIC_SCL_1();
HAL_Delay(1);
IIC_SDA_0();
HAL_Delay(1);
IIC_SCL_0();
}
void IIC_Stop(void)
{
SDA_OUT_MODE();
IIC_SCL_0();
IIC_SDA_0();
IIC_SCL_1();
HAL_Delay(1);
IIC_SDA_1();
HAL_Delay(1);
}
void IIC_SendByte(uint8_t ucByte)
{
uint8_t i;
SDA_OUT_MODE();
IIC_SCL_0();
for (i = 0; i < 8; i++)
{
if (ucByte & 0x80)
{
IIC_SDA_1();
}
else
{
IIC_SDA_0();
}
ucByte <<= 1;
HAL_Delay(1);
IIC_SCL_1();
HAL_Delay(1);
IIC_SCL_0();
HAL_Delay(1);
}
}
uint8_t IIC_ReadByte(void)
{
uint8_t i = 0;
uint8_t value = 0;
SDA_IN_MODE();
for (i = 0; i < 8; i++)
{
value <<= 1;
IIC_SCL_1();
HAL_Delay(1);
if (IIC_SDA_READ())
{
value++;
}
IIC_SCL_0();
HAL_Delay(1);
}
IIC_Ack();
return value;
}
uint8_t IIC_WaitAck(void)
{
uint8_t result = 0;
SDA_IN_MODE();
IIC_SDA_1();
HAL_Delay(1);
IIC_SCL_1();
HAL_Delay(1);
if (IIC_SDA_READ())
{
result = 1;
}
else
{
result = 0;
}
IIC_SCL_0();
HAL_Delay(1);
return result;
}
void IIC_Ack(void)
{
SDA_OUT_MODE();
IIC_SDA_0();
HAL_Delay(1);
IIC_SCL_1();
HAL_Delay(1);
IIC_SCL_0();
HAL_Delay(1);
IIC_SDA_1();
}
void IIC_NAck(void)
{
SDA_OUT_MODE();
IIC_SDA_1();
HAL_Delay(1);
IIC_SCL_1();
HAL_Delay(1);
IIC_SCL_0();
HAL_Delay(1);
}
uint8_t IIC_CheckDevice(uint8_t address)
{
uint8_t ucAck;
IIC2_Init();
IIC_Start();
IIC_SendByte(address);
ucAck = IIC_WaitAck();
IIC_Stop();
return ucAck;
}
static void SDA_OUT_MODE(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = IIC_SDA_PIN;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
}
static void SDA_IN_MODE(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.Pin = IIC_SDA_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_INPUT;
HAL_GPIO_Init(IIC_SDA_PORT, &GPIO_InitStructure);
}
TM1650驱动
这边在老哥的基础上增加了对字符 A P V的显示
static uint8_t s_7number[13] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F, 0x73, 0x3E, 0x77}; // 7display 0~9 %(P) V A
static uint8_t s_8number[13] = {0xBF, 0x86, 0xDB, 0xCF, 0xE6, 0xED, 0xFD, 0x87, 0xFF, 0xEF, 0xF3, 0xBE, 0xF7}; // 8display 0~9 %(P) V A
void TM1650_Write(uint8_t addr, uint8_t data)
{
IIC_Start();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_SendByte(data);
IIC_Ack();
IIC_Stop();
}
void TM1650_SetDisplay(uint8_t brightness, uint8_t mode, uint8_t state)
{
if(state)
{
if(mode == 7) // 7display
{
TM1650_Write(0x48, brightness*16 + 1*4 + 1);
}
else if(mode == 8) // 8display
{
TM1650_Write(0x48, brightness*16 + 1);
}
}
else
{
TM1650_Write(0x48, 0x00); // close
}
}
void TM1650_SetNumber(uint8_t index, uint8_t mode, uint8_t num)
{
uint8_t indexAddr = 0;
uint8_t numValue = 0;
if(index == 1)
{
indexAddr = 0x68;
}
else if(index == 2)
{
indexAddr = 0x6A;
}
else if(index == 3)
{
indexAddr = 0x6C;
}
else if(index == 4)
{
indexAddr = 0x6E;
}
if(mode == 7) // 7display
{
numValue = s_7number[num];
}
else if(mode == 8) // 8display
{
numValue = s_8number[num];
}
TM1650_Write(indexAddr, numValue);
}
电压电流显示
这边应用层 对电压采用两位整数一位小数的显示方式,对电流采用一位整数两位小数的显示方式
int current_display(float current)
{
int display_num;
TM1650_SetDisplay(3, 8, 0);
if (current <= 0)
{
return OPEN_ERR;
}
TM1650_SetDisplay(0, 8, 1);
if (current > 10)
{
display_num = (int)(current * 0.1f);
TM1650_SetNumber(1, 7, (display_num % 10));
}
else
{
TM1650_SetNumber(1, 7, 0);
}
if (current >= 1)
{
display_num = (int)current;
TM1650_SetNumber(2, 8, (display_num % 10));
}
else
{
TM1650_SetNumber(2, 8, 0);
}
display_num = (int)(current*10.0f);
TM1650_SetNumber(3, 7, (display_num % 10));
TM1650_SetNumber(4, 7, A);
return OK;
}
int voltage_display(float voltage)
{
int display_num;
TM1650_SetDisplay(3, 8, 0);
if (voltage <= 0)
{
return OPEN_ERR;
}
TM1650_SetDisplay(0, 8, 1);
if (voltage > 10)
{
display_num = (int) (voltage *0.1f);
TM1650_SetNumber(1, 7, display_num % 10);
}
else
{
TM1650_SetNumber(1, 7, 0);
}
if (voltage >= 1)
{
display_num = (int) voltage;
TM1650_SetNumber(2, 8, (display_num % 10));
}
else
{
TM1650_SetNumber(2, 8, 0);
}
display_num = (int) (voltage * 10.0f);
TM1650_SetNumber(3, 7, (display_num % 10));
TM1650_SetNumber(4, 7, V);
return OK;
}