数码之家

标题: 单片机I/O口无序直驱LED数码管程序分享 [打印本页]

作者: 慕名而来    时间: 2021-9-11 20:02
标题: 单片机I/O口无序直驱LED数码管程序分享
本帖最后由 慕名而来 于 2021-9-11 20:05 编辑

最近坛里有坛友 @iritwq 发帖请教数码管编程问题,帖子:初学C,数码管编程问题求教https://www.mydigit.cn/thread-275008-1-1.html(出处: 数码之家) ,在参与回复的时候发现它的4位数码管与单片机的连接不是用一组完整8位的I/O引脚来驱动8段LED数码,而是无序连接的,自从玩单片机以来也玩过很多的数码管驱动,但是基本都是通过164或595进行串口驱动,极少用到I/O直驱,更没有弄过任意接线的I/O口无序驱动,恰逢这几天没啥玩的,就找出了数码管通过飞线焊了一个4位数码块,编写了程序实物测试了一下,感觉也不难驱动,程序留存于此也分享给用得到的新手。
1.在此特别感谢上述帖子回复中的第32楼的坛友 @1065307738  我在他的代码中学到了将分散的位变量映射到一个变量的各个位的方法,通过这个方法使程序更加简练易懂。

2.硬件电路只用于演示,不讨论单片机I/O口分配的合理性。

原理图:

[attach]1273878[/attach]

分享程序:

  1. /**本程序用于测试分散I/O口驱动4位数码管显示**/
  2. #include <STC12C5A60S2.h>
  3. #include <intrins.h>
  4. #define uint unsigned int
  5. #define uchar unsigned char
  6. //----I/O口位功能定义-----------------------------------
  7. sbit da=P1^2;
  8. sbit db=P1^1;
  9. sbit dc=P0^1;
  10. sbit dd=P0^2;
  11. sbit de=P0^3;
  12. sbit df=P1^3;
  13. sbit dg=P1^4;
  14. sbit dp=P0^0;

  15. sbit w1=P0^4;
  16. sbit w2=P0^5;
  17. sbit w3=P0^6;
  18. sbit w4=P0^7;

  19. //不含小数点8段LED字形码0-9+黑屏码、共阳极驱动0亮1熄
  20. uchar duan_ma[11]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
  21. uchar wei_ma[4]= {0x07,0x0b,0x0d,0x0e}; //字位码
  22. uchar date[4];//显示数据暂存
  23. //====熄屏延时a*1ms延时函数===============================
  24. void delay_1ms (uchar a)        //@12.000MHz
  25. {
  26.     uchar i, j;
  27.     while(a--)
  28.     {
  29.         _nop_();
  30.         _nop_();
  31.         i = 12;
  32.         j = 168;
  33.         do
  34.         {
  35.             while (--j);
  36.         }
  37.         while (--i);
  38.     }
  39. }
  40. //====显示颜色a*10us=====================================
  41. void delay_10us(uchar a)                //@12.000MHz
  42. {
  43.     uchar i;
  44.     while(a--)
  45.     {
  46.         i = 27;
  47.         while (--i);
  48.     }
  49. }
  50. //=======================================================
  51. //将LED字形的8个笔段控制I/O引脚映射到变量的8个位上
  52. void segment_out(uchar dat)
  53. {
  54.     da=(bit)(dat&0x01);
  55.     db=(bit)(dat&0x02);
  56.     dc=(bit)(dat&0x04);
  57.     dd=(bit)(dat&0x08);
  58.     de=(bit)(dat&0x10);
  59.     df=(bit)(dat&0x20);
  60.     dg=(bit)(dat&0x40);
  61.     dp=(bit)(dat&0x80);
  62. }
  63. //=======================================================
  64. //将4个数位控制I/O引脚映射到变量的4个位上
  65. void position_out(uchar dat)
  66. {
  67.     w1=(bit)(dat&0x08);
  68.     w2=(bit)(dat&0x04);
  69.     w3=(bit)(dat&0x02);
  70.     w4=(bit)(dat&0x01);
  71. }
  72. //====数据拆分函数=======================================
  73. //提取出数据的千、百、十、个位的数值存入数组中
  74. void digits_obtain(uint dat)
  75. {
  76.     date[0]=dat/1000;
  77.     date[1]=dat%1000/100;
  78.     date[2]=dat%100/10;
  79.     date[3]=dat%10;
  80. }
  81. //====显示输出函数=======================================
  82. void display_out(uint dat)
  83. {
  84.     uchar i;
  85.     digits_obtain(dat);                //拆分数据
  86.     for(i=0; i<4; i++)
  87.     {
  88.         if(date[0]==0)                //如果第一位为0则屏蔽掉
  89.         {
  90.             date[0]=10;
  91.         }
  92.         else
  93.         {
  94.             segment_out(duan_ma[date[i]]);        //发送段显示码
  95.             position_out(wei_ma[i]);                //发送位显示码
  96.             if(i==1)                                                //点亮百位与十位中间的小数点、最大显示数据为99.99
  97.             {
  98.                 dp=0;
  99.             }
  100.             else
  101.             {
  102.                 dp=1;
  103.             }
  104.         }
  105. //以下为消隐及显示亮度调整部分
  106.         delay_10us(20);                                //显示时间、赋值变化可以改变显示亮度
  107.         segment_out(duan_ma[10]);        //送黑屏码
  108.         delay_1ms(5);                                //熄屏时间
  109.     }
  110. }
  111. //====主函数==============================================
  112. main()
  113. {
  114.     P0M1=0x00;
  115.     P0M0=0xff;                //P0口的8个引脚设定为推挽输出
  116.     P1M1=0x00;
  117.     P1M0=0x1e;                //P1.1、P1.2、P1.3、P1.4设定为推挽输出
  118.     while(1)
  119.     {
  120.         display_out(1234);
  121.     }
  122. }
复制代码


实物显示图片:

[attach]1273892[/attach]








作者: 广东梁百万    时间: 2021-9-11 22:34
本帖最后由 广东梁百万 于 2021-9-11 23:03 编辑

下面这个是我年初针对STC8G1K17   SOP-20 +  LCD1602写的程序(部分),就是用不是同一组的I/O口拼成一组8位数据口给LCD1602的D0~D7.

重点留意  bdata 这个数据类型   ,跟着把端口P1^2定义成LCD_D0 , 再在程序里对LCD_D0 进行位操作
那位1065307738大神用的  DA=(bit)(Dat&0x01); 进行位操作比我的更简洁,但下面程序的作法是我自己摸索出来的,所以我还是习惯了用我自己的方法:lol:


   sbit  LCD_D0  =  P1^2;
   sbit  LCD_D1  =  P1^3 ;
   sbit  LCD_D2  =  P3^2 ;
   sbit  LCD_D3  =  P3^3 ;
   sbit  LCD_D4  =  P3^4 ;
   sbit  LCD_D5  =  P3^5 ;
   sbit  LCD_D6  =  P3^6 ;
   sbit  LCD_D7  =  P3^7;
   sbit  LCD_RS  =  P1^0;   //LCD1602 的 RS端  ,1-数据,0-指令
   sbit  LCD_EN  =  P1^1 ;  //LCD1602 的 E端   ,先从低变高,再变低,以确认输入数据或命令



         
         unsigned char bdata LCD1602RAM2;  //LCD1602的写入缓冲    ********* 重点留意  bdata 这个数据类型

         sbit LCD1602RAM2_D0= LCD1602RAM2^0;
         sbit LCD1602RAM2_D1= LCD1602RAM2^1;
         sbit LCD1602RAM2_D2= LCD1602RAM2^2;
         sbit LCD1602RAM2_D3= LCD1602RAM2^3;
         sbit LCD1602RAM2_D4= LCD1602RAM2^4;
         sbit LCD1602RAM2_D5= LCD1602RAM2^5;
         sbit LCD1602RAM2_D6= LCD1602RAM2^6;
         sbit LCD1602RAM2_D7= LCD1602RAM2^7;

//-----------------------------------------------------------------------


                 //LCD1602数据写入
                        void LCD1602SZ()
                   {
                         LCD_RS=1;
                        LCD_EN=1;
                   LCD_D0=LCD1602RAM2_D0;
                   LCD_D1=LCD1602RAM2_D1;
                   LCD_D2=LCD1602RAM2_D2;
                   LCD_D3=LCD1602RAM2_D3;
                   LCD_D4=LCD1602RAM2_D4;
                   LCD_D5=LCD1602RAM2_D5;
                   LCD_D6=LCD1602RAM2_D6;
                   LCD_D7=LCD1602RAM2_D7;
                    LCD_EN=0;  //E,下降沿,让LCD读取
                         Delay60us();  //延时80us

                        }


                         //LCD1602指令写入
                        void LCD1602ZL()
                        {
                        LCD_RS=0;
                        LCD_EN=1;
                   LCD_D0=LCD1602RAM2_D0;
                   LCD_D1=LCD1602RAM2_D1;
                   LCD_D2=LCD1602RAM2_D2;
                   LCD_D3=LCD1602RAM2_D3;
                   LCD_D4=LCD1602RAM2_D4;
                   LCD_D5=LCD1602RAM2_D5;
                   LCD_D6=LCD1602RAM2_D6;
                   LCD_D7=LCD1602RAM2_D7;
                    LCD_EN=0;                 //E,下降沿,让LCD读取
                        Delay60us();  //延时80us

                        }





                        //LCD1602初始化
                        void LCD1602CCH()
                        {
                        
                        LCD1602RAM2=0;
                        delay_ms(15);          //延时15毫秒
                        LCD1602RAM2=0x38;  //;16行*2,5*8
                        LCD1602ZL();         //写入指令
                   delay_ms(5);          //延时5毫秒
                   LCD1602RAM2=0x38;  //;16行*2,5*8
                        LCD1602ZL();         //写入指令
                   delay_ms(5);          //延时5毫秒
                   LCD1602RAM2=0x08; // 关显示
                   LCD1602ZL();         //写入指令
                   delay_ms(1);          //延时1毫秒
                  LCD1602RAM2=0x01;        //清屏
                   LCD1602ZL();         //写入指令
                   delay_ms(5);          //延时5毫秒
                   LCD1602RAM2=0x06;        //;地址计数器AC自动加1,光标右移 *******
                   delay_ms(1);          //延时1毫秒
                   LCD1602RAM2=0x0C;        //开显示
                  LCD1602ZL();         //写入指令
                   delay_ms(1);          //延时1毫秒
                  
                   }



                // LCD1602全屏显示程序,16字*2行


                  void LCD1602SC()
                   {
                   unsigned char i=16;          //每行的个数计数
                   unsigned char x=0;                 //行数
                   unsigned char y=0;                //列数
                  
                   LCD1602RAM2=0x80;   //这个是LCD第1行的地址
                   LCD1602ZL(); //以地址/指令形式发送到LCD1602

                   while(i--)
                   {
                   LCD1602RAM2=LCD1602RAM1[0][y];
                   LCD1602SZ(); //以数据形式发送到LCD1602
                   y++;
                   };

               LCD1602RAM2=0xC0;   //这个是LCD第2行的地址
                   LCD1602ZL(); //以地址/指令形式发送到LCD1602
                   i=16        ;                 //每行的个数计数
                   y=0;        //每行的个数
                   while(i--)
                   {
                   LCD1602RAM2=LCD1602RAM1[1][y];
                   LCD1602SZ(); //以数据形式发送到LCD1602
                   y++;
                   };
                  
                   }









作者: 慕名而来    时间: 2021-9-12 10:01
广东梁百万 发表于 2021-9-11 22:34
下面这个是我年初针对STC8G1K17   SOP-20 +  LCD1602写的程序(部分),就是用不是同一组的I/O口拼成一组8 ...

多谢你的经验分享,以前有了解过bdata数据类型,多是在ILI9431彩屏驱动等例程中用到,但我没有用过,如果不是借鉴坛友的方法我自己写的话就是如下结构了:
  1. void zi_xing(uchar c)//字形生成函数
  2. {
  3. switch(c)
  4. {
  5. case 0:               
  6. {
  7. da=0;db=0;dc=0;dd=0;de=0;df=0;dg=1;//0
  8. }
  9. break;
  10. case 1:               
  11. {
  12. da=1;db=0;dc=0;dd=1;de=1;df=1;dg=1;//1
  13. }
  14. break;
  15. case 2:               
  16. {
  17. da=0;db=0;dc=1;dd=0;de=0;df=1;dg=0;//2
  18. }
  19. break;
  20. case 3:               
  21. {
  22. da=0;db=0;dc=0;dd=0;de=1;df=1;dg=0;//3
  23. }
  24. break;
  25. case 4:               
  26. {
  27. da=1;db=0;dc=0;dd=1;de=1;df=0;dg=0;//4
  28. }
  29. break;
  30. case 5:               
  31. {
  32. da=0;db=1;dc=0;dd=0;de=1;df=0;dg=0;//5
  33. }
  34. break;
  35. case 6:               
  36. {
  37. da=0;db=0;dc=0;dd=0;de=0;df=1;dg=0;//6
  38. }
  39. break;
  40. case 7:               
  41. {
  42. da=0;db=0;dc=0;dd=1;de=1;df=1;dg=1;//7
  43. }
  44. break;
  45. case 8:               
  46. {
  47. da=0;db=0;dc=0;dd=0;de=0;df=0;dg=0;//8
  48. }
  49. break;
  50. case 9:               
  51. {
  52. da=0;db=0;dc=0;dd=0;de=1;df=0;dg=0;//9
  53. }
  54. break;
  55. case 10:               
  56. {
  57. da=1;db=1;dc=1;dd=1;de=1;df=1;dg=1;//黑屏
  58. }
  59. break;
  60. default:
  61. break;
  62. }
复制代码


字形生成函数的代码非常直观,虽然省掉了字模数组但看起来还是繁琐些,调用也是一样的:zi_xing(date);//其中date对应显示数据拆分后的某一位数据。

作者: iritwq    时间: 2021-9-12 19:10
都是大神呀,膜拜中。。。。。。
作者: 慕名而来    时间: 2021-9-12 19:59
iritwq 发表于 2021-9-12 19:10
都是大神呀,膜拜中。。。。。。

只是喜欢玩单片机,因为C编程是看例程学习的所以一直很外行,只会改编程序不会起头写程序。
作者: 595953427@qq    时间: 2021-9-14 23:19
广东梁百万 发表于 2021-9-11 22:34
下面这个是我年初针对STC8G1K17   SOP-20 +  LCD1602写的程序(部分),就是用不是同一组的I/O口拼成一组8 ...

这是基本常识了,keilC51的变前面可以加data idata xdata bdata,各修饰有各自的用处,keilC51的帮助有说明的。
但是不建议这样写,这样只能用在keilC51上面,换了IDE或芯片内核就用不了,建议使用共用体union,标准C编译器都支持。
作者: 慕名而来    时间: 2021-9-15 08:54
595953427@qq 发表于 2021-9-14 23:19
这是基本常识了,keilC51的变前面可以加data idata xdata bdata,各修饰有各自的用处,keilC51的帮助有说 ...

希望大神能够给出用共用体union的代码,很想学习这种方法先谢了!
作者: iritwq    时间: 2021-9-15 09:09
慕名而来 发表于 2021-9-15 08:54
希望大神能够给出用共用体union的代码,很想学习这种方法先谢了!

http://c.biancheng.net/cpp/html/2932.html我在这里看到一个介绍,看的云里雾里的,感觉不到这种方法有什么用处


通过前面的讲解,我们知道结构体(Struct)是一种构造类型或复杂类型,它可以包含多个类型不同的成员。在C语言中,还有另外一种和结构体非常类似的语法,叫做共用体(Union),它的定义格式为:
union 共用体名{
    成员列表
};

共用体有时也被称为联合或者联合体,这也是 Union 这个单词的本意。
结构体和共用体的区别在于:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

结构体占用的内存大于等于所有成员占用的内存的总和(成员之间可能会存在缝隙),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

共用体也是一种自定义类型,可以通过它来创建变量,例如:
union data{
    int n;
    char ch;
    double f;
};
union data a, b, c;
上面是先定义共用体,再创建变量,也可以在定义共用体的同时创建变量:
union data{
    int n;
    char ch;
    double f;
} a, b, c;
如果不再定义新的变量,也可以将共用体的名字省略:
union{
    int n;
    char ch;
    double f;
} a, b, c;
共用体 data 中,成员 f 占用的内存最多,为 8 个字节,所以 data 类型的变量(也就是 a、b、c)也占用 8 个字节的内存,请看下面的演示:
#include <stdio.h>
union data{
    int n;
    char ch;
    short m;
};
int main(){
    union data a;
    printf("%d, %d\n", sizeof(a), sizeof(union data) );
    a.n = 0x40;
    printf("%X, %c, %hX\n", a.n, a.ch, a.m);
    a.ch = '9';
    printf("%X, %c, %hX\n", a.n, a.ch, a.m);
    a.m = 0x2059;
    printf("%X, %c, %hX\n", a.n, a.ch, a.m);
    a.n = 0x3E25AD54;
    printf("%X, %c, %hX\n", a.n, a.ch, a.m);
   
    return 0;
}
运行结果:
4, 4
40, @, 40
39, 9, 39
2059, Y, 2059
3E25AD54, T, AD54
这段代码不但验证了共用体的长度,还说明共用体成员之间会相互影响,修改一个成员的值会影响其他成员。
作者: iritwq    时间: 2021-9-15 09:20
595953427@qq 发表于 2021-9-14 23:19
这是基本常识了,keilC51的变前面可以加data idata xdata bdata,各修饰有各自的用处,keilC51的帮助有说 ...

初学者真是举步维艰呀,复制的代码一个没动,编译时到处出问题
[attach]1276899[/attach]

作者: 595953427@qq    时间: 2021-9-15 12:29
iritwq 发表于 2021-9-15 09:20
初学者真是举步维艰呀,复制的代码一个没动,编译时到处出问题

你写的不对,不是这样的。
作者: 595953427@qq    时间: 2021-9-15 12:40
[attach]1277043[/attach]
  1. #include "reg52.h"

  2. typedef union
  3. {
  4.     unsigned char val;
  5.     struct
  6.     {
  7.         unsigned char bit_0 : 1;
  8.         unsigned char bit_1 : 1;
  9.         unsigned char bit_2 : 1;
  10.         unsigned char bit_3 : 1;
  11.         unsigned char bit_4 : 1;
  12.         unsigned char bit_5 : 1;
  13.         unsigned char bit_6 : 1;
  14.         unsigned char bit_7 : 1;
  15.     } bit_n;
  16. } un_8;

  17. un_8 un8;

  18. void main(void)
  19. {
  20.     un8.val = 0xFF;
  21.     un8.bit_n.bit_0 = 0;
  22.     un8.bit_n.bit_1 = 1;
  23.     un8.bit_n.bit_2 = 0;
  24.     un8.bit_n.bit_3 = 1;
  25.     un8.bit_n.bit_4 = 0;
  26.     un8.bit_n.bit_5 = 1;
  27.     un8.bit_n.bit_6 = 0;
  28.     un8.bit_n.bit_7 = 1;
  29.     while (1)
  30.     {
  31.         un8.val++;
  32.     }
  33. }
复制代码



作者: 595953427@qq    时间: 2021-9-15 12:41
iritwq 发表于 2021-9-15 09:20
初学者真是举步维艰呀,复制的代码一个没动,编译时到处出问题

你看一下11楼,我没有写注释,应该能看懂吧。
作者: 595953427@qq    时间: 2021-9-15 12:52
本帖最后由 595953427@qq 于 2021-9-15 13:13 编辑

仔细看一下有没有使用bdata的区别。
bdata是好用,但是也有限制的,bdata只有16个字节。
16个字节,每个字节8位,一共128位,你在程序里面定义的bit型变量也包含在这128位里面。
bdata虽好,数量有限,且用且珍惜。
[attach]1277058[/attach][attach]1277059[/attach]

作者: 595953427@qq    时间: 2021-9-15 12:58
还是vs code看着舒服。
墙裂建议使用vs code,使用结构体,共用体的时候代码提示会非常方便。
[attach]1277072[/attach]
[attach]1277073[/attach][attach]1277074[/attach][attach]1277075[/attach][attach]1277076[/attach]

作者: 595953427@qq    时间: 2021-9-15 13:02
慕名而来 发表于 2021-9-12 10:01
多谢你的经验分享,以前有了解过bdata数据类型,多是在ILI9431彩屏驱动等例程中用到,但我没有用过,如果 ...

你这个代码排版也太不友好了,建议使用vs code,按下快捷键alt + shift + F,会给你整理好排版。
作者: 595953427@qq    时间: 2021-9-15 13:17
同样的代码使用Keil4编译结果和Keil5编译结果相差这么大?
[attach]1277081[/attach][attach]1277082[/attach]

作者: 595953427@qq    时间: 2021-9-15 15:10
iritwq 发表于 2021-9-15 09:09
http://c.biancheng.net/cpp/html/2932.html我在这里看到一个介绍,看的云里雾里的,感觉不到这种方法有 ...

共用体还有个作用很方便,就是要把float类型的数据保存到eeprom,或者UART通讯的时候传输float类型的数据,用共用体会很方便。
作者: 595953427@qq    时间: 2021-9-15 15:11
iritwq 发表于 2021-9-15 09:20
初学者真是举步维艰呀,复制的代码一个没动,编译时到处出问题

你这样肯定是编译不通过的,变量名不可以使用关键字。data在keilC51里面是关键字,不能用作变量名。
作者: iritwq    时间: 2021-9-15 17:08
595953427@qq 发表于 2021-9-15 15:11
你这样肯定是编译不通过的,变量名不可以使用关键字。data在keilC51里面是关键字,不能用作变量名。 ...

改成这样编译倒是通过了,但是不知道怎样才能出来运行的结果[attach]1277258[/attach]


作者: 595953427@qq    时间: 2021-9-15 23:56
iritwq 发表于 2021-9-15 17:08
改成这样编译倒是通过了,但是不知道怎样才能出来运行的结果

你在单片机上用过printf吗?需要配合串口使用的,通过串口打印。
作者: iritwq    时间: 2021-9-16 08:23
595953427@qq 发表于 2021-9-15 23:56
你在单片机上用过printf吗?需要配合串口使用的,通过串口打印。

原来如此,谢谢您指导
作者: 慕名而来    时间: 2021-9-16 13:31
595953427@qq 发表于 2021-9-15 13:02
你这个代码排版也太不友好了,建议使用vs code,按下快捷键alt + shift + F,会给你整理好排版。 ...

你好,3#的代码是我在文本文档中写完了粘贴过来的,所以不成样子、如果是在keil中通过Astyle排版后就是1#的样子了,感觉还是可以接受的,感谢你的推荐。
作者: wdb8899    时间: 2021-12-30 22:17
楼主你好,//将LED字形的8个笔段控制I/O引脚映射到变量的8个位上
void segment_out(uchar dat)
{
    da=(bit)(dat&0x01);
    db=(bit)(dat&0x02);
    dc=(bit)(dat&0x04);
    dd=(bit)(dat&0x08);
    de=(bit)(dat&0x10);
    df=(bit)(dat&0x20);
    dg=(bit)(dat&0x40);
    dp=(bit)(dat&0x80);
}
这段语句看不懂,比如dat为0xc0,他是怎么么映射的?
作者: 慕名而来    时间: 2022-1-1 20:29
你在草纸上用二进制将数据展开再配合硬件驱动方式就容易理解了,da到dp这8个位从左到右排列对应dat的8个位,本例中是低电平有效驱动数码管的,低电平位点亮相应字段,高电平熄灭相应段,如果dat为0xc0则字码的中间一横(dg)和小数点(dp)将熄灭而其他段将被点亮将显示字符0,有时候单纯看代码或许迷糊,上手实验一下就容易理解了。
作者: motofanoranw    时间: 2022-3-20 19:59
用这个程序编译刷机后数码管亮度很暗,因为代码最后一段的推挽输出我不知道应该怎么调整。下面是我用坛友@1065307738https://www.mydigit.cn/thread-275008-2-1.html帖子里的的代码,我用的I/O口已调整好,也是无序的,编译刷机后显示亮度正常了,但还有一个问题就是我的3、4两个数码管是倒着装的,这个翻转180的代码如何编写,请坛友指点。谢谢谢谢
  1. <blockquote><blockquote>#include "STC15.H"
复制代码



作者: 慕名而来    时间: 2022-3-21 14:07
motofanoranw 发表于 2022-3-20 19:59
用这个程序编译刷机后数码管亮度很暗,因为代码最后一段的推挽输出我不知道应该怎么调整。下面是我用坛友@1 ...

数码管倒装后字符颠倒的问题怎样解决暂且不说,先说说为什么字符颠倒,说到这个问题就接着我在楼上的回复在说说这个字模数组:uchar duan_ma[11]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};

它的生成的依据就是数码管与单片机端口的接线顺序,以完整端口P1驱动8位段码为例,
如果接线为P1.0=A,P1.1=B,P1.2=C,P1.3=D,P1.4=E,P1.5=F,P1.6=G,P1.7=DP0(本帖虽然不是同一个I/O,但函数中的定义也遵循这样个规律,比如:da=(bit)(dat&0x01);就是bit0对应A脚的定义)
那么可以得到如下表格:

[attach]1435621[/attach]

如果将数码管颠倒后安装的话,引脚的位置变化了,此时对应的表格如下:

[attach]1435622[/attach]

根据新的表格就可以写一个新的数组,这就不难理解了,如果你对编程不是很熟悉,那么根据我的画格子的方法编写数组是最简单的方法,当然了还有更简单的方法就是在网上找一个数码管辅助小软件,设置好引脚对应关系可以自动得到数据表的。
字模数组编好了后,程序中用到相应位显示引用不同的数组就能正确显示了。



作者: motofanoranw    时间: 2022-3-21 18:33
谢谢指导,按照你的方法再把画好的数码管颠倒过来就可以很清晰的看到对应了。
作者: motofanoranw    时间: 2022-3-21 20:03
不过如何在你发的代码中修改3、4颠倒的数字呢,再建一个字模数组吗?请指教。
作者: motofanoranw    时间: 2022-3-21 20:07
如果用坛友@elecfunwb加DataR的方法,应该如何加入开篇的代码中。
  1. void DataR(unsigned char Dat)
  2. {
  3.         DD=(bit)(Dat&0x01);
  4.         DE=(bit)(Dat&0x02);
  5.         DF=(bit)(Dat&0x04);
  6.         DA=(bit)(Dat&0x08);
  7.         DB=(bit)(Dat&0x10);
  8.         DC=(bit)(Dat&0x20);
  9.         DG=(bit)(Dat&0x40);
  10.         DP=(bit)(Dat&0x80);
  11. }
复制代码

作者: xueyeteng    时间: 2023-7-12 16:40
坛子里的大神好多,学习了。
作者: xueyeteng    时间: 2023-7-12 16:41
motofanoranw 发表于 2022-3-21 20:07
如果用坛友@elecfunwb加DataR的方法,应该如何加入开篇的代码中。

楼主用的不就是这种方法吗?
作者: STC32位8051    时间: 2023-7-12 17:27
提示: 作者被禁止或删除 内容自动屏蔽




欢迎光临 数码之家 (https://www.mydigit.cn/) Powered by Discuz! X3.4