找回密码
 立即注册
查看: 929|回复: 1

STC89C52驱动 16x64LED点阵模块驱动记录(七)像画布一样操作点阵屏

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:568
  • 最近打卡:2025-07-04 08:00:54

17

主题

65

回帖

1944

积分

金牌会员

积分
1944
发表于 2023-11-24 22:05:20 | 显示全部楼层 |阅读模式
前言
        LED点阵模块也是显示屏,显示屏就不只是用来显示文字,还应该可以用来画图。

        那么一个可以绘图的显示屏应该具有哪些条件:

        1)要有一块区域做为显存,就是要显示的数据,在单片机中为了节约空间要用位来控制led亮灭。一个字节8位,可以控制8个led。16x64LED就需要16x64/8=128个字节的显存,在单片机中用数组表示。

        2)显存有了,就需要绘图函数来控制数组的值。这部分涉及的数学方面的知识,还有对位的控制,比较烧脑,超出个人能力。所以我问了AI,它给了我一段程序,见后文。

        3)下一步,就回归正题,在单片机显示。没有新花样,还是行扫描,595。


一、像画布一样操作点阵屏源码
1.main.c
  1. #include <STC89C5xRC.H>
  2. #include <intrins.h>
  3. #include <absacc.h>
  4. #include <string.h>
  5. #include "draw.h"
  6. sbit SH_CP = P1^5;
  7. sbit DS = P2^7;
  8. sbit ST_CP = P1^6;
  9. typedef unsigned int Uint16;
  10. typedef unsigned char Uint8;
  11. extern unsigned char xdata canvas[WIDTH * HEIGHT / 8];
  12. void Delay1000ms()                //@11.0592MHz
  13. {
  14.         unsigned char i, j, k;
  15.         _nop_();
  16.         i = 8;
  17.         j = 1;
  18.         k = 122;
  19.         do
  20.         {
  21.                 do
  22.                 {
  23.                         while (--k);
  24.                 } while (--j);
  25.         } while (--i);
  26. }
  27. void delayms(unsigned int m)
  28. {
  29.         int i,j;
  30.         for(i=0; i<m; i++)
  31.                 for(j=0; j<120; j++);
  32. }
  33. //595就是串行输入,凑足8个并行输出,SH_CP上升沿管串行输入
  34. void HC595(unsigned char dat)
  35. {
  36.         unsigned char j;
  37.         for(j=0;j<8;j++)
  38.         {
  39.                 SH_CP = 0;        //为移位准备
  40.                 DS = dat & 0x01;        //先低位
  41.                 dat=dat>>1;
  42.                 //DS=dat&0x80;
  43.                 //dat=dat<<1;
  44.                 SH_CP =1;          //上升沿,移位
  45.         }
  46. }
  47. void drawbuff()
  48. {
  49.         unsigned char i,j,n,index;
  50.         for(n=0;n<24;n++)    //为了字不闪
  51.         {
  52.                 for(j=0;j<16;j++)
  53.                 {
  54.                         for(i=0;i<8;i++)
  55.                         {
  56.                                         index=i+j*8;
  57.                                         HC595(~canvas[index]);       
  58.                         }
  59.                         ST_CP = 0;
  60.                         ST_CP = 1;
  61.                         P1=15-j;
  62.                         Delay1000ms();
  63.                         P1=0xff;
  64.                 }
  65.         }
  66. }
  67. void testLed()
  68. {
  69.         unsigned char k,i,j,dat;
  70.         for(k=0;k<16;k++)
  71.         {
  72.                 for(i=0;i<4;i++)
  73.                 {
  74.             HC595(0x00);
  75.                         HC595(0x00);
  76.                 }
  77.                 ST_CP = 0;
  78.                 ST_CP = 1;
  79.                 P1=k;
  80.                 _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
  81.                 _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
  82.                 _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
  83.                 P1=0xff;
  84.         }
  85.        
  86. }
  87. void main(){
  88.         clearScreen();
  89.         testLed();       
  90.         draw_rectangle(0, 0,10, 20, 1);
  91.         draw_rectangle(2, 25,10, 31, 0);
  92.         draw_line(10, 20, 15, 30);
  93.         draw_point(10,48);
  94.         draw_circle(8, 36 , 8, 0);
  95.         while(1){
  96.                 drawbuff();
  97.         }
  98. }
复制代码
2.绘图实现文件draw.c

        下面程序是AI生成的,在windows环境下运行基本正常。移植到51上,改了一些类型定义,有部分函数不太正常了。比如画直线的draw_line函数。

        另外需要注意的是,所有函数中x为纵坐标,y为横坐标。

  1. #include <stdio.h>
  2. #include <math.h>
  3. #include "draw.h"
  4. unsigned char xdata canvas[WIDTH * HEIGHT / 8]; // 画布,使用一个字节的位来表示一个点是否被画
  5. // 画点
  6. void draw_point(unsigned int x, unsigned int y) {
  7.     unsigned int index = x * HEIGHT + y; // 计算该点在 canvas 中的下标
  8.     canvas[index / 8] |= 1 << (index % 8); // 将该点的位置置为 1
  9. }
  10. // 擦除点
  11. void erase_point(unsigned int x, unsigned int y) {
  12.     unsigned int index = x * HEIGHT + y; // 计算该点在 canvas 中的下标
  13.     canvas[index / 8] &= ~(1 << (index % 8)); // 将该点的位置置为 0
  14. }
  15. // 判断点是否被画
  16. unsigned int is_point_drawn(unsigned int x, unsigned int y) {
  17.     unsigned int index = x * HEIGHT + y; // 计算该点在 canvas 中的下标
  18.     return canvas[index / 8] & (1 << (index % 8)); // 判断该点的位置是否为 1
  19. }
  20. // 画线
  21. void draw_line(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2) {
  22.     unsigned int dx = x2 - x1; // 计算 x 轴方向的增量
  23.     unsigned int dy = y2 - y1; // 计算 y 轴方向的增量
  24.     unsigned int incr = 1; // 确定增量的方向
  25.                 unsigned int x,y,d;
  26.     if (dx < 0) { // 如果 x 轴增量为负数,则将增量方向翻转
  27.         dx = -dx;
  28.         dy = -dy;
  29.         incr = -1;
  30.     }
  31.     x = x1, y = y1; // 初始点的坐标
  32.     d = 0; // 决策变量
  33.     draw_point(x, y); // 先画初始点
  34.     while (x != x2) { // 沿着 x 轴方向依次画点
  35.         x += incr;
  36.         d += dy;
  37.         if (d >= dx) { // 如果决策变量超过了 dx,则需要向 y 轴方向移动一格
  38.             y++;
  39.             d -= dx;
  40.         } else if (d <= -dx) { // 如果决策变量小于了 -dx,则需要向 y 轴方向移动一格
  41.             y--;
  42.             d += dx;
  43.         }
  44.         draw_point(x, y); // 画当前点
  45.     }
  46. }
  47. // 画矩形
  48. void draw_rectangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int fill) {
  49.     unsigned int x, y;
  50.     if (x1 > x2) { // 如果 x1 大于 x2,则交换两个点的坐标
  51.         int temp = x1;
  52.         x1 = x2;
  53.         x2 = temp;
  54.     }
  55.     if (y1 > y2) { // 如果 y1 大于 y2,则交换两个点的坐标
  56.         unsigned int temp = y1;
  57.         y1 = y2;
  58.         y2 = temp;
  59.     }
  60.     // 画上下两条边
  61.     for (x = x1; x <= x2; x++) {
  62.         draw_point(x, y1);
  63.         draw_point(x, y2);
  64.     }
  65.     // 画左右两条边
  66.     for (y = y1; y <= y2; y++) {
  67.         draw_point(x1, y);
  68.         draw_point(x2, y);
  69.     }
  70.     if (fill) { // 如果需要填充,则将矩形内部的点全部画上
  71.         for (x = x1 + 1; x < x2; x++) {
  72.             for (y = y1 + 1; y < y2; y++) {
  73.                 draw_point(x, y);
  74.             }
  75.         }
  76.     }
  77. }
  78. // 画圆
  79. void draw_circle(unsigned int x, unsigned int y, unsigned int r, unsigned int fill) {
  80.     unsigned int dx = 0, dy = r;
  81.     unsigned int d = 1 - r;
  82.                 unsigned i;
  83.     draw_point(x + dx, y + dy);
  84.     draw_point(x + dx, y - dy);
  85.     draw_point(x + dy, y + dx);
  86.     draw_point(x + dy, y - dx);
  87.     while (dx < dy) {
  88.         dx++;
  89.         if (d < 0) {
  90.             d = d + 2 * dx + 1;
  91.         } else {
  92.             dy--;
  93.             d = d + 2 * (dx - dy) + 1;
  94.         }
  95.         if (fill) { // 如果需要填充,则画圆内部的点
  96.             for (i = x - dx + 1; i < x + dx; i++) {
  97.                 draw_point(i, y + dy);
  98.                 draw_point(i, y - dy);
  99.             }
  100.             for (i = x - dy + 1; i < x + dy; i++) {
  101.                 draw_point(i, y + dx);
  102.                 draw_point(i, y - dx);
  103.             }
  104.         } else { // 否则只画圆上的点
  105.             draw_point(x + dx, y + dy);
  106.             draw_point(x + dx, y - dy);
  107.             draw_point(x - dx, y + dy);
  108.             draw_point(x - dx, y - dy);
  109.             draw_point(x + dy, y + dx);
  110.             draw_point(x + dy, y - dx);
  111.             draw_point(x - dy, y + dx);
  112.             draw_point(x - dy, y - dx);
  113.         }
  114.     }
  115. }
  116. // 画椭圆
  117. void draw_ellipse(unsigned int x, unsigned int y, unsigned int a, unsigned int b, unsigned int fill) {
  118.     unsigned int aa = a * a;
  119.     unsigned int bb = b * b;
  120.     unsigned int aa2 = 2 * aa;
  121.     unsigned int bb2 = 2 * bb;
  122.     unsigned int x0 = x - a;
  123.     unsigned int x1 = x + a;
  124.     unsigned int y0 = y - b;
  125.     unsigned int y1 = y + b;
  126.     unsigned int dx = a / sqrt(aa + bb);
  127.     unsigned int dy = dx * b / a;
  128.     unsigned int sx = x - dx;
  129.     unsigned int ex = x + dx;
  130.                 unsigned int y2;
  131.     if (fill) { // 填充椭圆
  132.         for ( y2 = y0 + 1; y2 < y1; y2++) {
  133.             int x02 = aa * (y - y0 - 1) * (y - y0 - 1); // (y-1)^2*a^2
  134.             int x12 = aa * (y - y1) * (y - y1); // (y- y1)^2*a^2
  135.             for (y2 = x02 / aa + x0 + 1; y2 < x1 - x12 / aa - 1; y2++) {
  136.                 draw_point(x, y);
  137.             }
  138.         }
  139.     } else { // 画椭圆
  140.         int x = 0, y = b;
  141.         int d = bb - aa * b + aa / 4;
  142.         while (bb2 * x < aa2 * y) {
  143.             draw_point(x0 + x, y0 + y);
  144.             draw_point(x1 - x, y0 + y);
  145.             draw_point(x0 + x, y1 - y);
  146.             draw_point(x1 - x, y1 - y);
  147.             if (d < 0) {
  148.                 x++;
  149.                 d += bb2 * x + bb;
  150.             } else {
  151.                 x++;
  152.                 y--;
  153.                 d += bb2 * x - aa2 * y + bb;
  154.             }
  155.         }
  156.         d = bb * (x + 0.5) * (x + 0.5) + aa * (y - 1) * (y - 1) - aa * bb;
  157.         while (y >= 0) {
  158.             draw_point(x0 + x, y0 + y);
  159.             draw_point(x1 - x, y0 + y);
  160.             draw_point(x0 + x, y1 - y);
  161.             draw_point(x1 - x, y1 - y);
  162.             if (d > 0) {
  163.                 y--;
  164.                 d += aa - aa2 * y;
  165.             } else {
  166.                 x++;
  167.                 y--;
  168.                 d += bb2 * x - aa2 * y + aa;
  169.             }
  170.         }
  171.     }
  172. }
  173. // 画三角形
  174. void draw_triangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int x3, unsigned int  y3, unsigned int fill) {
  175.     if (fill) { // 填充三角形
  176.         int x, y, x_min, x_max, y_min, y_max;
  177.         x_min = x1 < x2 ? (x1 < x3 ? x1 : x3) : (x2 < x3 ? x2 : x3);
  178.         x_max = x1 > x2 ? (x1 > x3 ? x1 : x3) : (x2 > x3 ? x2 : x3);
  179.         y_min = y1 < y2 ? (y1 < y3 ? y1 : y3) : (y2 < y3 ? y2 : y3);
  180.         y_max = y1 > y2 ? (y1 > y3 ? y1 : y3) : (y2 > y3 ? y2 : y3);
  181.         for (x = x_min + 1; x < x_max; x++) { // 遍历所有可能的点
  182.             for (y = y_min + 1; y < y_max; y++) {
  183.                 if (((x2 - x1) * (y - y1) - (y2 - y1) * (x - x1)) * ((x3 - x2) * (y - y2) - (y3 - y2) * (x - x2)) * ((x1 - x3) * (y - y3) - (y1 - y3) * (x - x3)) < 0) { // 用叉积判断当前点是否在三角形内部
  184.                     draw_point(x, y); // 如果在则画点
  185.                 }
  186.             }
  187.         }
  188.     } else { // 画三角形
  189.         draw_line(x1, y1, x2, y2);
  190.         draw_line(x2, y2, x3, y3);
  191.         draw_line(x3, y3, x1, y1);
  192.     }
  193. }
  194. // 显示画布
  195. void showcanvas() {
  196.         unsigned int y ,x;
  197.         for ( y = 0; y < HEIGHT; y++) {
  198.         for (x = 0; x < WIDTH; x++) {
  199.         putchar(is_point_drawn(x, y) ? '1' : '0'); // 根据点是否被画来输出 0 或 1
  200.         } putchar('\n');
  201.         }
  202. }
  203. void clearScreen(){
  204.         unsigned i,j;
  205.         for(i=0;i<WIDTH;i++)
  206.         for(j=0;j<HEIGHT/8;j++)
  207.         {
  208.                 canvas[i*8+j]=0x00;
  209.         }
  210. }
复制代码
3.绘图功能头文件:draw.h

        关于画图的函数都在这里了:

  1. #ifndef __CANVAS_DRAW_H__
  2. #define _CANVAS_DRAW_H__
  3. /
  4. //
  5. // 画图程序 by AI,20230508
  6. //
  7. #define WIDTH 16 // 画布宽度
  8. #define HEIGHT 64 // 画布高度
  9. // 画点
  10. void draw_point(unsigned int x, unsigned int y);
  11. // 擦除点
  12. void erase_point(unsigned int x, unsigned int y) ;
  13. // 判断点是否被画
  14. unsigned int is_point_drawn(unsigned int x, unsigned int y);
  15. // 画线
  16. void draw_line(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2) ;
  17. // 画矩形
  18. void draw_rectangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int fill);
  19. // 画圆
  20. void draw_circle(unsigned int x, unsigned int y, unsigned int r, unsigned int fill);
  21. // 画椭圆
  22. void draw_ellipse(unsigned int x, unsigned int y, unsigned int a, unsigned int b, unsigned int fill) ;
  23. // 画三角形
  24. void draw_triangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int x3, unsigned int y3, unsigned int fill) ;
  25. // 显示画布
  26. void showcanvas() ;
  27. void clearScreen();
  28. /
  29. #endif
复制代码

99e526d354e142d0ba18630f50b546d1.jpg



回复

使用道具 举报 送花

  • 打卡等级:常住居民III
  • 打卡总天数:117
  • 最近打卡:2025-07-04 09:38:12

743

主题

1万

回帖

1万

积分

管理员

积分
17396
发表于 2023-11-25 08:08:14 | 显示全部楼层
可以尝试下【USB直接仿真 / USB直接下载】的STC8H8K64U
截图202311250807483626.jpg
www.stcai.com



回复 支持 反对

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2025-7-4 17:10 , Processed in 0.143401 second(s), 54 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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