开发板:STM8L
阅读芯片手册
参考网址:https://item.szlcsc.com/45446.html#pdf-view 点击 “数据手册PDF” 栏目,就可以看到详细的介绍。 另一个较为详细的参考资料链接:https://max.book118.com/html/2022/0514/8041072017004101.shtm
调试遇到的问题
1:数据的写入
根据芯片手册所述,会有配置地址 0x48,正常理解不应该是这样的: {bit[7] bit[6] bit[5] bit[4] bit[3] bit[2] bit[1] bit[0] ACK bit[7] bit[6] bit[5] bit[4] bit[3] bit[2] bit[1] bit[0] } 数据线上的波形表现是:start 0 1 0 0 1 0 0 0 0 set[7]…set[0] 0 stop (注:斜体数字是来自芯片回复) 疑问:结束前倒数第二个时钟对应的数据被拉低了一截,这样反而代表是正确的,原因未知。示波器抓图如下:
2:数码管不亮
确定正确写入要显示的数据以后,数码管依旧不亮。 经过仔细观察,是硬件电阻选用错误导致数码管驱动电流太小亮的不明显。需要仔细的甄别。 也可以配合单步调试,测试芯片的8段输出电平,看是否与写入情况一致。只要一致芯片就是用起来了。 至于数码管不亮,是另外的分析环节。ps:相关帖子有人说采用共阳极的不行。没遇到过,不知真假。
3:数码管调试模式亮,正常运行不亮
首先确认单片机上电程序加载成功,其他代码也正常运行了。但是只有数码管不亮。 用示波器抓波也可以看到数据有在下发,然后就想到配置距离数字显示功能函数的时延太大了。把初始化提到数字显示前一步,显示正常。后面在显示数字功能函数前加了设置功能函数就好了。这点比较特殊。
TM1650的应用补充——仅适用于LED驱动
亮度
亮度设置从1~8级,级别越高,亮度越大。
片选信号DIG
低有效(低电平代表选中数码管)。可以用来测试配置是否成功。 以DIG4为例, 配置寄存器配置前,此引脚输出高电平。配置生效后,输出方波。经过测试是频率223.5Hz,占空比75%的方波,具体波形参考图:
配置顺序
必须先进行配置寄存器写入(此芯片也可用于矩阵按键的识别,是配置寄存器的不同将功能分化),再进行下一步显示数值的设置。关于这里补充一下,配置寄存器不是开机初始化一次后面直接写数据就可以的,而是最好每次写入显示数据前都重新配置一次。本人在STM8采用初始化配置,后期写数的情况出现了异常:调试模式显示数字没问题,断电重启就不显示数字,调了好久,特此提醒。
代码分享
开发板:STM8L 库函数版本
dv_TM1650.h
#ifndef DV_TM1650_H #define DV_TM1650_H
// dv_TM1650 //IIC所有操作函数
void gpio_IIC_Start(void); void gpio_IIC_Stop(void); void gpio_IIC_Send_Byte(char dat); char IIC_SDA_RD(); char gpio_IIC_Wait_Ack(void);
void TM1650_Init(void); //初始化IIC的IO口 void TM1650_Set(unsigned char light , unsigned char mode ); void TM1650_Show_Num(unsigned char pleft , unsigned char pright ); void TM1650_IIC_8addr8data(unsigned char regaddr , unsigned char param); void TM1650_Set_Num(unsigned char addr , unsigned char value ,unsigned char point);
#endif /* DV_TM1650_H */
dv_TM1650.c
#include “stm8l10x.h” #include <stdio.h>
#include “dv_TM1650.h” #include <iostm8l101f3.h>
#include “delay_user.h”
//主机拉高拉低SCL #define IIC_SCL_HIGH GPIO_SetBits(GPIOB , GPIO_Pin_6); //SCL out1 #define IIC_SCL_LOW GPIO_ResetBits(GPIOB , GPIO_Pin_6); //SCL out0 //主机拉高拉低SDA #define IIC_SDA_HIGH GPIO_SetBits(GPIOB , GPIO_Pin_7); #define IIC_SDA_LOW GPIO_ResetBits(GPIOB , GPIO_Pin_7); //输出 SDA
//参数bit为1时,主机拉高SDA,非1时,主机拉低SDA #define IIC_SDA_WR(bit) do{if(bit) GPIO_SetBits(GPIOB,GPIO_Pin_7); else GPIO_ResetBits(GPIOB,GPIO_Pin_7); }while(0);
//#define I2C_SPEED 100000 //调试通过 unsigned char data; //全局变量,设置寄存器的值。
/******************************************************************************* **函数名称:void TM1650_Init() **功能描述:初始化TM1650的控制接口 **入口参数: **输出:无 //调试通过 *******************************************************************************/ void TM1650_Init(void) { GPIO_Init(GPIOB , GPIO_Pin_6 , GPIO_Mode_Out_PP_High_Fast); // GPIO_Mode_In_FL_No_IT GPIO_Init(GPIOB , GPIO_Pin_7 , GPIO_Mode_Out_PP_High_Fast); // SDA
IIC_SCL_HIGH; //设置PB6输出高电平
IIC_SDA_HIGH; //设置PB7输出高电平
data= 0x01; //全局变量,设置寄存器的值。
//TM1650_Set(8,8);
}
void gpio_IIC_Start(void) //发送IIC开始信号 { IIC_SCL_HIGH; IIC_SDA_HIGH; delay_us(2); IIC_SDA_LOW; delay_us(2); IIC_SCL_LOW; }
void gpio_IIC_Stop(void) //发送IIC停止信号 { IIC_SCL_LOW; IIC_SDA_LOW; delay_us(2); IIC_SCL_HIGH; delay_us(2); IIC_SDA_HIGH; }
void gpio_IIC_Send_Byte(char dat) //IIC主机向从机发送一个字节 { char i; char data_iic, data_bit;
data_iic = dat;
IIC_SCL_LOW;
for(i=0; i<8; i++){
data_bit = (data_iic&0x80)>>7;
IIC_SDA_WR(data_bit);
data_iic = data_iic <<1;
delay_us(1);
IIC_SCL_HIGH;
delay_us(1);
IIC_SCL_LOW;
delay_us(1);
}
IIC_SDA_LOW;
}
char IIC_SDA_RD() //添加此函数会打乱周期,故未使用,未调试 { char rack = 0; GPIO_Init(GPIOB , GPIO_Pin_7 , GPIO_Mode_In_PU_No_IT); // 初始化KEY1,设置PA_3为上拉电阻输入并且禁止中断模式 delay_us(2); rack = GPIO_ReadInputDataBit(GPIOA , GPIO_Pin_3); // 判断数据线的回复值 GPIO_Init(GPIOB , GPIO_Pin_7 , GPIO_Mode_Out_PP_Low_Fast);// 恢复SDA的输出方向 return rack; } char gpio_IIC_Wait_Ack(void) //IIC主机等待从机返回的ACK应答信号 { //char ack = 0;
delay_us(1);
IIC_SCL_HIGH;
delay_us(1);
IIC_SCL_LOW;
//if(IIC_SDA_RD())
// ack = 1;
delay_us(2);
return 0;//ack;
}
/******************************************************************************* **函数名称:void TM1650_IIC_8addr8data(unsigned char regaddr , unsigned char param) **功能描述:向TM1650器件写配置数据,没有子设备地址的概念 **入口参数: regaddr: 写的寄存器地址 param : 写的数据值 **输出:无 //调试通过 *******************************************************************************/ void TM1650_IIC_8addr8data(unsigned char regaddr , unsigned char param) { gpio_IIC_Start(); //gpio_IIC_Send_Byte(regaddr<<1); gpio_IIC_Send_Byte(regaddr); gpio_IIC_Wait_Ack();
gpio_IIC_Send_Byte(param);
gpio_IIC_Wait_Ack();
gpio_IIC_Stop();
}
/******************************************************************************* **函数名称:void IIC_8addr8Read(unsigned char subaddr , unsigned char Byte_addr , unsigned char *buffer , unsigned short num) **功能描述:向IIC器件读数据 **入口参数: subaddr : 从器件地址 Byte_addr : 确定器件写地址的起始地址 *buffer : 读数据的缓冲区起始地址 num : 要读数据的个数 **输出:无 *******************************************************************************/ void IIC_8addr8Read(unsigned char subaddr , unsigned char Byte_addr , unsigned char *buffer , unsigned short num) {
}
/******************************************************************************* **函数名称:void TM1650_Set() **功能描述:设置数码管显示的相关参数。 **入口参数: light:亮度显示1~8级。8级最亮,其他数字按照4级亮度处理。 mode:7or8段显示。7是7段,8是8段,其他数字按照8段处理。 **输出:无 //调试通过 *******************************************************************************/ void TM1650_Set(unsigned char light , unsigned char mode ) { unsigned char cmd; cmd = 0x48; //置的固定指令
data &= 0x0F; //先将高4位清0,//全局变量,设置寄存器的值。
switch(light){
case 1:
data |= 0x10; break;
case 2:
data |= 0x20; break;
case 3:
data |= 0x30; break;
case 4:
data |= 0x40; break;
case 5:
data |= 0x50; break;
case 6:
data |= 0x60; break;
case 7:
data |= 0x70; break;
case 8:
data |= 0x00; break;
default:
data |= 0x40; break;
}
data &= 0xF7; //先将data[3]清0
switch(mode){
case 7:
data |= 0x08; break;
case 8:
data |= 0x00; break;
default:
data |= 0x00; break;
}
TM1650_IIC_8addr8data(cmd,data); //设置亮度和几段
return;
}
/******************************************************************************* **函数名称:void TM1650_Show_Num() **功能描述:设置数码管显示的数值。 **入口参数: pleft: 整数部分的数字。(0~99) pright:小数部位的数字。(0~99) **输出:无 //调试通过 *******************************************************************************/ void TM1650_Show_Num(unsigned char pleft , unsigned char pright ) { unsigned char DIG1_num, DIG2_num, DIG3_num, DIG4_num;
TM1650_Set(8,8);
DIG1_num = pleft/10; //整数 十位数
TM1650_Set_Num(0x68,DIG1_num,0); //设置具体的数值
delay_ms(100);
DIG2_num = pleft%10; //整数 个位数,带小数点
TM1650_Set_Num(0x6A,DIG2_num,1);
delay_ms(100);
DIG3_num = pright/10; //小数 十位数
TM1650_Set_Num(0x6C,DIG3_num,0);
delay_ms(100);
DIG4_num = pright%10; //小数 个位数
TM1650_Set_Num(0x6E,DIG4_num,0);
delay_ms(100);
}
/******************************************************************************* **函数名称:void TM1650_Set_Num() **功能描述:设置数码管显示的数值。 **入口参数: addr: 位选地址。 value:共阴极数码管显示的数字,和驱动数字不一致,需要编码转换。Byte[dp,g,f,e,d,c,b,a] point: 是否点亮小数点 **输出:无 //调试通过 *******************************************************************************/ void TM1650_Set_Num(unsigned char addr , unsigned char value ,unsigned char point) { char write_num = 0x00; char show_num[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7F,0x6f}; //0~9 //共阴极的数码映射
if(value <=9) // 0<= value &
write_num = show_num[value];
else
write_num = 0x00;
if(point)
write_num |= 0x80;
TM1650_IIC_8addr8data(addr,write_num);
}
附件:数据手册PDF截图(共5页)
|