浦江一水 发表于 2024-4-14 17:23:32

基于STC32G12K128实验箱V9.62_实验之数码管显示字符串


许多单片机学习开发板,都带有数码管显示模块,STC32G12K128实验箱V9.62版实验箱,也不例外, 带有8位数码管。
可见单片机驱动数码管显示, 是一项基本功技术, 必须学习掌握的。
八段数码管笔划少,可显示的字符有局限,但显示数值型数据应该是足以胜任的,因此一些电子产品常用之。
看似简单,但对于新手来说,数值转段码,加之要动态扫描,稳定显示,编程上其实有一定难度,是不能小觑的 。
......
那么, 如果要显示一个数值,例如圆周率 3.14,或者显示多小数位 3.14159,该如何显示呢?
当然,对应数码管的位数,首先要有一个显示缓存区,将需要显示的数字一个一个转换成段码往里填就是了......
经常能看到例程中有类似这样的代码:
   temp1=temp;
   qian=temp1/1000;
   bai=temp1%1000/100;
   shi=temp1%100/10;      
   ge=temp1%10;

为了显示一个四位数, 要四次除以、取整、求余.....   当然, 这个算法是绝对没错的, 也可谓是经典的....
但如果要显示一个6位数呢? 或者显示数值小数点后位数是不同的呢? 那么显示算法都要分别重写了, 而且代码的行数显然也是不同的了....


是否能写一个函数, 以不变应万变呢? 于是就尝试做了这样的实验: 数码管显示字符串函数...
先看看效果:
视频中,
先显示一个字符串 "Stc-Abcd",延时3秒...(体现直接显示字符串)
再显示:   "P=3.14159" ,延时3秒...      (亮相PI值,体现字母符号+小数显示)

再显示:   "d= 1.234 " ,延时3秒...          (直径数据,体现小数点后不同位数的显示)


再显示:   "F=1.19597" , 延时3秒...          (面积数据)

再循环显示: 时-分-秒                               (体现整型数值的显示)








浦江一水 发表于 2024-4-14 17:24:10

本帖最后由 浦江一水 于 2024-4-14 17:32 编辑

主程序 Main.C
( 主频 24MHz )



//********************************************************************************
// 名称: 实验8位数码管动态扫描显示
// 基于: STC32G12K128 V9.62 实验箱
// 实验: STC32G工程创建/STC-USB-Link1D仿真器调试/GPIO基本输出控制/定时器x中断...
// 编程: 浦晓明(浦江一水) 2023-12-10
//********************************************************************************
#include "STC32G_SYS.H"
#include "LED8D.H"


#definePI         3.14159


/************* 全局变量声明 **************/
char S;                  //显示字符串缓存
unsigned char hour;   //时
unsigned char minute;//分
unsigned char second;//秒
float    d,F;                  //直径和面积


/*************外部函数声明和外部变量声明 *****************/


//========================================================================

// 函数: voiddelay_ms(unsigned int ms)
// 描述: 毫秒级延时函数。
// 参数: ms,要延时的ms数,自动适应主时钟.
//=====================================================================
voiddelay_ms(unsigned int ms)
{ unsigned int i;
do{ i = MAIN_Fosc / 6000;
      while(--i);
    } while(--ms);
}
/********************** RTC演示函数 ***********************/
void RTC(void)
{
if(++second >= 60)
{ second = 0;
    if(++minute >= 60)
    { minute = 0;
      if(++hour >= 24) hour = 0;
    }
}
sprintf(S,"%02d-%02d-%02d",hour,minute,second);//组织字符串
LED8D_Str(0,S);                                  //送显示段码缓存   
}
/******************** 主函数 **************************/
void main(void)
{
SYS_Init();      //系统初始化
LED8D_Init();    //8数码管初始化

d=1.234;          //直径m
F=PI*d*d/4;   //求面积

LED8D_Str(0,"Stc-ABcD");   //字符串常量直接显示   
delay_ms(3000);                  //延时一下
sprintf(S,"P=%6.5f",PI);       //浮点数转字符串显示PI值
LED8D_Str(0,S);                  //送显示段码缓存   
delay_ms(3000);                  //延时一下
sprintf(S,"D= %5.3f ",d);      //浮点数转字符串显示d直径值
LED8D_Str(0,S);                  //送显示段码缓存   
delay_ms(3000);                  //延时一下
sprintf(S,"F=%6.5f",F);         //浮点数转字符串显示F面积值
LED8D_Str(0,S);                  //送显示段码缓存   
delay_ms(3000);                  //延时一下

hour   = 11;    //时间初始化
minute = 59;
second = 58;
RTC();
//循环...整型数转字符串显示...
while(1)
{
    if(SecOK)   //1s到
    { SecOK = 0;
      RTC();
    }
}
}


//完整工程源码文件见1楼

浦江一水 发表于 2024-4-14 17:25:05

本帖最后由 浦江一水 于 2024-4-14 17:47 编辑

显示函数详解



//********************************************************************************
// 名称: LED8D.H LED_8位数码管驱动头文件
// 基于: STC32G12K128 V9.62 实验箱
// 实验: C251编译环境搭建/STC32G工程创建/STC-USB-Link1D仿真器调试/GPIO基本输出控制...
//       数码管动态扫描显示...
// 硬件: P6--8段数据 P7--8位驱动
// 编程: 浦晓明(浦江一水) 2023-12-13
//********************************************************************************
#ifndef__LED8D_H
#define__LED8D_H


#include "STC32G_SYS.H"       //参考STC库函数, 局部修改...自备用.               
#include "STC32G_GPIO.H" //参考STC库函数, 局部修改...自备用.
#include "STC32G_TIMER.H" //参考STC库函数, 局部修改...自备用.


extern bit SecOK;                  //秒到标志


//***** 端口功能初始化函数说明 *********************************************
void LED8D_Init(void);            //初始化
void LED8D_Str(u8 x,u8 * str);   //定位x显示字符串


#endif




//********************************************************************************
// 名称: LED8D.C LED_8位数码管
// 基于: STC32G12K128 V9.62 实验箱
// 实验: C251编译环境搭建/STC32G工程创建/STC-USB-Link1D仿真器调试/GPIO基本输出控制...
//       数码管动态扫描显示...
// 硬件: P6--8段数据 P7--8位驱动
// 编程: 浦晓明(浦江一水) 2023-12-10
//********************************************************************************
#include "LED8D.H"

/************* 用户定义宏 ***********************/
#define T0_Reload   (65536UL -(MAIN_Fosc / 1000))       //Timer 0 中断频率, 1000次/秒
/************* 本地常量声明    *******************/
u8 code LedC[]={ "0123456789ABCDEF -HJKLNoPUtGqryhnuc=_S" };                                                         //可显示字符38
u8 code LedD[]={ 0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,//0..9,A..F   段码...

               0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x6E,0x7C,            //...h          段码...

               0x54,0x1C,0x58,0x48,0x08,0x6D,         };                                                                              //n..._         段码...

u8 code T_COM[]={ 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01,};                                                            //位码

/************* 本地变量声明    **************/
u8LED8;      //显示段码缓冲
u8DispN;          //显示位索引
bit SecOK;          //秒到标志
unsigned int msecond; //毫秒
/************* 本地函数声明    **************/

//***** LED8位数码管初始化函数 ******************************
void LED8D_Init(void)
{
SetGPIO_MODE(6,0xFF,3);   //设P6口全部为开漏输出模式 //等效写法: SetGPIO_MODE(GPIO_P6,Pin_All,GPIO_OUT_OD);
SetGPIO_MODE(7,0xFF,0);   //设P7口全部为准双向口模式 //等效写法: SetGPIO_MODE(GPIO_P7,Pin_All,GPIO_PullUp);
//P6=0x80;P7=0x7F;
TimerInit(0,0,1,(u16)T0_Reload); //定时器0模式:16位自动重载模式,12T...
TimerNVIC(0,0,1);         //定时器0中断(优先级0)使能
DispN=0; msecond=0; EA=1;   //开中断..
}
//*** 定位x显示字符串 ****************************************
void LED8D_Str(u8 x,u8 * str)
{ unsigned char ch,y,i;
if(x>=8)return;             //超界..返回..
for(;x<8;x++)            //从指定位置x到7
{ y=0;
    for(i=0;i<38;i++)       //根据字符查找对应段码
    { if(*str==LedC)      //找到匹配
      { ch=LedD;         //取出段码
      y=1; break;            //找到标志y   
      } else ch=0x00;      //若无对应段码则用0空替代.
    }
    if(y==1)                  //有可显示字符...
    { if(*(str+1)=='.')       //如果遇小数点处理...
      { ch |= 0x80;         //段码最高位置1...(加小数点)
      str++;                   //字符串指针移动

      }
      LED8=ch;             //定位写入显示
    }
    str++;                        //字符串指针移动
    if(*str=='\0')break;      //字符串结束
}
}
//************************* 显示扫描函数 *******************

void DisplayScan(void)                //由定时器0每1ms调用一次   8位数码管8ms动态扫描显示一遍.
{   
    P7 = ~T_COM;         //移位驱动
    P6 = ~LED8;            //段码送出
    if(++DispN >= 8)DispN = 0;//8位结束回0
}
//========================================================================
// 函数: Timer0_ISR_Handler
// 描述: Timer0中断函数.
//========================================================================
void Timer0_ISR_Handler (void) interrupt TMR0_VECTOR                //进中断时已经清除标志
{
msecond++;            //毫秒计数...
if(msecond>=1000){ SecOK=1; msecond=0; }
DisplayScan();            //1ms扫描显示一位
}

//**** RunLED END *********************************************




_奶咖君_ 发表于 2024-4-14 17:36:57

确实,,直接统一按照字符串来解析 要比获取一位一位的数字要简单很多,

,,如果资源比较充裕还可以使用类似sprintf函数来生成字符串,十分好用,所见即所得,

如果要移植其他的位数的芯片 只用做好字库适配,,不同芯片实际的写入函数的方法,就可以按照以前的方式来使用,

xxxevery 发表于 2024-4-14 18:36:01

不错,学习了

浦江一水 发表于 2024-4-14 19:08:01

_奶咖君_ 发表于 2024-4-14 17:36
确实,,直接统一按照字符串来解析 要比获取一位一位的数字要简单很多,

,,如果资源比较充裕还可以使用类似 ...

确实是金牌会员, 一眼就看出了使用sprintf()函数, 本实验就是, 在写具体函数应用时, 就简单多了.
谢谢您的浏览回复.

顺便聊一句, sprintf()函数在C251编译器环境下,有时会出现很奇怪的现象, 原因尚未搞清楚. 相比较在C51编译器环境下,要好一点.在Keil MDK for STM32 环境下, 从未出现过问题. 感觉 C251 比较小众,对STC32G并未全心支持...

浦江一水 发表于 2024-4-14 19:08:34

xxxevery 发表于 2024-4-14 18:36
不错,学习了

谢谢您的浏览回复鼓励.我们共同学习....

王昱顺 发表于 2024-4-14 19:22:13

浦江一水 发表于 2024-4-14 19:08
确实是金牌会员, 一眼就看出了使用sprintf()函数, 本实验就是, 在写具体函数应用时, 就简单多了.
谢谢您 ...

应该是长度对齐问题,可以使用(int)进行类型强制转换后再次尝试,并且保证输入参数类型和实际对应

电子爱好者2024 发表于 2024-4-14 20:20:20

学习了

浦江一水 发表于 2024-4-14 21:22:31

王昱顺 发表于 2024-4-14 19:22
应该是长度对齐问题,可以使用(int)进行类型强制转换后再次尝试,并且保证输入参数类型和实际对应 ...

谢谢您的提醒指点...

根据坛子里坛友的一些疑问帖子来看:
C251 对于STC32G
不支持局部变量、形参变量的仿真跟踪...
不支持strstr()函数...
不支持全局变量的动态刷新...
与KeilMDK for STM32的使用顺畅感受有许多不同,相差甚远...
这些不爽, 在学习使用STC32G中, 十分挫伤学习STC32G的热情...
故而一直存有两点疑惑:
1. C251 很小众, 本无全力支持你STC之意, Keil C 本应有的功能,到此失灵...
2. STC的仿真驱动程序算法不够强壮...
页: [1]
查看完整版本: 基于STC32G12K128实验箱V9.62_实验之数码管显示字符串