找回密码
 立即注册
查看: 60|回复: 11

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

[复制链接]
  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 143 天

    [LV.7]常住居民III

    5

    主题

    96

    回帖

    650

    积分

    高级会员

    积分
    650
    发表于 2024-4-14 17:23:32 | 显示全部楼层 |阅读模式

    许多单片机学习开发板,都带有数码管显示模块,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秒...          (面积数据)

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





    基于STC32G12K128实验箱V9.62_实验之数码管显示字符串.rar (31.17 KB, 下载次数: 0)


    回复 送花

    使用道具 举报

  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 143 天

    [LV.7]常住居民III

    5

    主题

    96

    回帖

    650

    积分

    高级会员

    积分
    650
     楼主| 发表于 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"


    #define  PI         3.14159


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


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


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

    // 函数: void  delay_ms(unsigned int ms)
    // 描述: 毫秒级延时函数。
    // 参数: ms,要延时的ms数,自动适应主时钟.
    //=====================================================================
    void  delay_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楼

    点评

    楼主威武 +1 ❀ 233  发表于 2024-4-14 17:37
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 143 天

    [LV.7]常住居民III

    5

    主题

    96

    回帖

    650

    积分

    高级会员

    积分
    650
     楼主| 发表于 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,};                                                            //位码

    /************* 本地变量声明    **************/
    u8  LED8[8];        //显示段码缓冲
    u8  DispN;          //显示位索引
    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[x]=ch;             //定位写入显示
        }
        str++;                        //字符串指针移动
        if(*str=='\0')break;      //字符串结束
      }
    }
    //************************* 显示扫描函数 *******************

    void DisplayScan(void)                //由定时器0每1ms调用一次   8位数码管8ms动态扫描显示一遍.
    {   
        P7 = ~T_COM[DispN];           //移位驱动
        P6 = ~LED8[DispN];              //段码送出
        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 *********************************************




    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    慵懒
    7 小时前
  • 签到天数: 134 天

    [LV.7]常住居民III

    20

    主题

    1039

    回帖

    2459

    积分

    金牌会员

    积分
    2459
    发表于 2024-4-14 17:36:57 | 显示全部楼层
    确实,,直接统一按照字符串来解析 要比获取一位一位的数字要简单很多,

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

    如果要移植其他的位数的芯片 只用做好字库适配,,不同芯片实际的写入函数的方法,就可以按照以前的方式来使用,
    参考例程并不是对技术参 考手册的补充,而是对技术参 考手册的解释。
    技术参 考手册不应该需要参考例程作为补充,而是解释成了参考例程的样子
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    慵懒
    6 小时前
  • 签到天数: 55 天

    [LV.5]常住居民I

    0

    主题

    177

    回帖

    336

    积分

    中级会员

    积分
    336
    发表于 2024-4-14 18:36:01 | 显示全部楼层
    不错,学习了
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 143 天

    [LV.7]常住居民III

    5

    主题

    96

    回帖

    650

    积分

    高级会员

    积分
    650
     楼主| 发表于 2024-4-14 19:08:01 | 显示全部楼层
    _奶咖君_ 发表于 2024-4-14 17:36
    确实,,直接统一按照字符串来解析 要比获取一位一位的数字要简单很多,

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

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

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

    点评

    应该是长度对齐问题,可以使用(int)进行类型强制转换后再次尝试,并且保证输入参数类型和实际对应  详情 回复 发表于 2024-4-14 19:22
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 143 天

    [LV.7]常住居民III

    5

    主题

    96

    回帖

    650

    积分

    高级会员

    积分
    650
     楼主| 发表于 2024-4-14 19:08:34 | 显示全部楼层

    谢谢您的浏览回复鼓励.  我们共同学习....
    回复 支持 反对 送花

    使用道具 举报

  • TA的每日心情
    开心
    7 小时前
  • 签到天数: 105 天

    [LV.6]常住居民II

    31

    主题

    386

    回帖

    1938

    积分

    荣誉版主

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

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

    使用道具 举报

  • TA的每日心情
    开心
    10 小时前
  • 签到天数: 57 天

    [LV.5]常住居民I

    8

    主题

    101

    回帖

    464

    积分

    中级会员

    积分
    464
    发表于 2024-4-14 20:20:20 | 显示全部楼层
    学习了
    回复 送花

    使用道具 举报

  • TA的每日心情
    开心
    8 小时前
  • 签到天数: 143 天

    [LV.7]常住居民III

    5

    主题

    96

    回帖

    650

    积分

    高级会员

    积分
    650
     楼主| 发表于 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的仿真驱动程序算法不够强壮...

    点评

    keil 好像对51单片机已经不怎么上心了,,可能得向其他的编译器努力了  发表于 2024-4-14 21:30
    回复 支持 反对 送花

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

    GMT+8, 2024-4-30 16:32 , Processed in 0.079598 second(s), 73 queries .

    Powered by Discuz! X3.5

    © 2001-2024 Discuz! Team.

    快速回复 返回顶部 返回列表