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

前言

        LED点阵模块也是显示屏,显示屏就不只是用来显示文字,还应该可以用来画图。

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

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

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

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


一、像画布一样操作点阵屏源码

1.main.c

#include <STC89C5xRC.H>
#include <intrins.h>
#include <absacc.h>
#include <string.h>
#include "draw.h"


sbit SH_CP = P1^5;
sbit DS = P2^7;
sbit ST_CP = P1^6;

typedef unsigned int Uint16;
typedef unsigned char Uint8;

extern unsigned char xdata canvas[WIDTH * HEIGHT / 8];

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 122;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}



void delayms(unsigned int m)
{
	int i,j;
	for(i=0; i<m; i++)
		for(j=0; j<120; j++);
}

//595就是串行输入,凑足8个并行输出,SH_CP上升沿管串行输入
void HC595(unsigned char dat)
{
	unsigned char j;
	for(j=0;j<8;j++)
	{
		SH_CP = 0;	//为移位准备
		DS = dat & 0x01;	//先低位
		dat=dat>>1;
		//DS=dat&0x80;
		//dat=dat<<1;
		SH_CP =1;  	//上升沿,移位
	}
}




void drawbuff()
{
	unsigned char i,j,n,index;
	for(n=0;n<24;n++)    //为了字不闪
	{
		for(j=0;j<16;j++)
		{

			for(i=0;i<8;i++)
			{
					index=i+j*8;
					HC595(~canvas[index]);	
			}
			ST_CP = 0;
			ST_CP = 1; 
			P1=15-j; 
			Delay1000ms();
			P1=0xff;
		}
	}
}



void testLed()
{
	unsigned char k,i,j,dat;
	for(k=0;k<16;k++)
	{
		for(i=0;i<4;i++)
		{
    	HC595(0x00);
			HC595(0x00);
		}
		ST_CP = 0;
		ST_CP = 1;
		P1=k;
		_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
		_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
		_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
		P1=0xff;
	}
	

}



void main(){
	clearScreen();
	testLed();	
	draw_rectangle(0, 0,10, 20, 1); 
	draw_rectangle(2, 25,10, 31, 0); 
	draw_line(10, 20, 15, 30); 
	draw_point(10,48);
	draw_circle(8, 36 , 8, 0); 
	while(1){
		drawbuff();
	}
}

2.绘图实现文件draw.c

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

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

#include <stdio.h>
#include <math.h>
#include "draw.h"


unsigned char xdata canvas[WIDTH * HEIGHT / 8]; // 画布,使用一个字节的位来表示一个点是否被画
// 画点
void draw_point(unsigned int x, unsigned int y) {
    unsigned int index = x * HEIGHT + y; // 计算该点在 canvas 中的下标
    canvas[index / 8] |= 1 << (index % 8); // 将该点的位置置为 1
}

// 擦除点
void erase_point(unsigned int x, unsigned int y) {
    unsigned int index = x * HEIGHT + y; // 计算该点在 canvas 中的下标
    canvas[index / 8] &= ~(1 << (index % 8)); // 将该点的位置置为 0
}

// 判断点是否被画
unsigned int is_point_drawn(unsigned int x, unsigned int y) {
    unsigned int index = x * HEIGHT + y; // 计算该点在 canvas 中的下标
    return canvas[index / 8] & (1 << (index % 8)); // 判断该点的位置是否为 1
}

// 画线
void draw_line(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2) {
    unsigned int dx = x2 - x1; // 计算 x 轴方向的增量
    unsigned int dy = y2 - y1; // 计算 y 轴方向的增量
    unsigned int incr = 1; // 确定增量的方向
		unsigned int x,y,d;
    if (dx < 0) { // 如果 x 轴增量为负数,则将增量方向翻转
        dx = -dx;
        dy = -dy;
        incr = -1;
    }
    x = x1, y = y1; // 初始点的坐标
    d = 0; // 决策变量
    draw_point(x, y); // 先画初始点
    while (x != x2) { // 沿着 x 轴方向依次画点
        x += incr;
        d += dy;
        if (d >= dx) { // 如果决策变量超过了 dx,则需要向 y 轴方向移动一格
            y++;
            d -= dx;
        } else if (d <= -dx) { // 如果决策变量小于了 -dx,则需要向 y 轴方向移动一格
            y--;
            d += dx;
        }
        draw_point(x, y); // 画当前点
    }
}

// 画矩形
void draw_rectangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int fill) {
    unsigned int x, y;
    if (x1 > x2) { // 如果 x1 大于 x2,则交换两个点的坐标
        int temp = x1;
        x1 = x2;
        x2 = temp;
    }
    if (y1 > y2) { // 如果 y1 大于 y2,则交换两个点的坐标
        unsigned int temp = y1;
        y1 = y2;
        y2 = temp;
    }
    // 画上下两条边
    for (x = x1; x <= x2; x++) {
        draw_point(x, y1);
        draw_point(x, y2);
    }
    // 画左右两条边
    for (y = y1; y <= y2; y++) {
        draw_point(x1, y);
        draw_point(x2, y);
    }
    if (fill) { // 如果需要填充,则将矩形内部的点全部画上
        for (x = x1 + 1; x < x2; x++) {
            for (y = y1 + 1; y < y2; y++) {
                draw_point(x, y);
            }
        }
    }
}

// 画圆
void draw_circle(unsigned int x, unsigned int y, unsigned int r, unsigned int fill) {
    unsigned int dx = 0, dy = r;
    unsigned int d = 1 - r;
		unsigned i;
    draw_point(x + dx, y + dy);
    draw_point(x + dx, y - dy);
    draw_point(x + dy, y + dx);
    draw_point(x + dy, y - dx);
    while (dx < dy) {
        dx++;
        if (d < 0) {
            d = d + 2 * dx + 1;
        } else {
            dy--;
            d = d + 2 * (dx - dy) + 1;
        }
        if (fill) { // 如果需要填充,则画圆内部的点
            for (i = x - dx + 1; i < x + dx; i++) {
                draw_point(i, y + dy);
                draw_point(i, y - dy);
            }
            for (i = x - dy + 1; i < x + dy; i++) {
                draw_point(i, y + dx);
                draw_point(i, y - dx);
            }
        } else { // 否则只画圆上的点
            draw_point(x + dx, y + dy);
            draw_point(x + dx, y - dy);
            draw_point(x - dx, y + dy);
            draw_point(x - dx, y - dy);
            draw_point(x + dy, y + dx);
            draw_point(x + dy, y - dx);
            draw_point(x - dy, y + dx);
            draw_point(x - dy, y - dx);
        }
    }
}

// 画椭圆
void draw_ellipse(unsigned int x, unsigned int y, unsigned int a, unsigned int b, unsigned int fill) {
    unsigned int aa = a * a;
    unsigned int bb = b * b;
    unsigned int aa2 = 2 * aa;
    unsigned int bb2 = 2 * bb;
    unsigned int x0 = x - a;
    unsigned int x1 = x + a;
    unsigned int y0 = y - b;
    unsigned int y1 = y + b;
    unsigned int dx = a / sqrt(aa + bb);
    unsigned int dy = dx * b / a;
    unsigned int sx = x - dx;
    unsigned int ex = x + dx;
		unsigned int y2;
    if (fill) { // 填充椭圆
        for ( y2 = y0 + 1; y2 < y1; y2++) {
            int x02 = aa * (y - y0 - 1) * (y - y0 - 1); // (y-1)^2*a^2
            int x12 = aa * (y - y1) * (y - y1); // (y- y1)^2*a^2
            for (y2 = x02 / aa + x0 + 1; y2 < x1 - x12 / aa - 1; y2++) {
                draw_point(x, y);
            }
        }
    } else { // 画椭圆
        int x = 0, y = b;
        int d = bb - aa * b + aa / 4;
        while (bb2 * x < aa2 * y) {
            draw_point(x0 + x, y0 + y);
            draw_point(x1 - x, y0 + y);
            draw_point(x0 + x, y1 - y);
            draw_point(x1 - x, y1 - y);
            if (d < 0) {
                x++;
                d += bb2 * x + bb;
            } else {
                x++;
                y--;
                d += bb2 * x - aa2 * y + bb;
            }
        }
        d = bb * (x + 0.5) * (x + 0.5) + aa * (y - 1) * (y - 1) - aa * bb;
        while (y >= 0) {
            draw_point(x0 + x, y0 + y);
            draw_point(x1 - x, y0 + y);
            draw_point(x0 + x, y1 - y);
            draw_point(x1 - x, y1 - y);
            if (d > 0) {
                y--;
                d += aa - aa2 * y;
            } else {
                x++;
                y--;
                d += bb2 * x - aa2 * y + aa;
            }
        }
    }
}

// 画三角形
void draw_triangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int x3, unsigned int  y3, unsigned int fill) {
    if (fill) { // 填充三角形
        int x, y, x_min, x_max, y_min, y_max;
        x_min = x1 < x2 ? (x1 < x3 ? x1 : x3) : (x2 < x3 ? x2 : x3);
        x_max = x1 > x2 ? (x1 > x3 ? x1 : x3) : (x2 > x3 ? x2 : x3);
        y_min = y1 < y2 ? (y1 < y3 ? y1 : y3) : (y2 < y3 ? y2 : y3);
        y_max = y1 > y2 ? (y1 > y3 ? y1 : y3) : (y2 > y3 ? y2 : y3);
        for (x = x_min + 1; x < x_max; x++) { // 遍历所有可能的点
            for (y = y_min + 1; y < y_max; y++) {
                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) { // 用叉积判断当前点是否在三角形内部
                    draw_point(x, y); // 如果在则画点
                }
            }
        }
    } else { // 画三角形
        draw_line(x1, y1, x2, y2);
        draw_line(x2, y2, x3, y3);
        draw_line(x3, y3, x1, y1);
    }
}

// 显示画布 
void showcanvas() { 
	unsigned int y ,x;
	for ( y = 0; y < HEIGHT; y++) { 
	for (x = 0; x < WIDTH; x++) { 
	putchar(is_point_drawn(x, y) ? '1' : '0'); // 根据点是否被画来输出 0 或 1 
	} putchar('\n'); 
	} 
}


void clearScreen(){
	unsigned i,j;
	for(i=0;i<WIDTH;i++)
	for(j=0;j<HEIGHT/8;j++)
	{
		canvas[i*8+j]=0x00;
	}
}

3.绘图功能头文件:draw.h

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

#ifndef __CANVAS_DRAW_H__
#define _CANVAS_DRAW_H__

/
//
// 画图程序 by AI,20230508
//

#define WIDTH 16 // 画布宽度
#define HEIGHT 64 // 画布高度




// 画点
void draw_point(unsigned int x, unsigned int y);

// 擦除点
void erase_point(unsigned int x, unsigned int y) ;

// 判断点是否被画
unsigned int is_point_drawn(unsigned int x, unsigned int y);

// 画线
void draw_line(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2) ;

// 画矩形
void draw_rectangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int fill);

// 画圆
void draw_circle(unsigned int x, unsigned int y, unsigned int r, unsigned int fill);

// 画椭圆
void draw_ellipse(unsigned int x, unsigned int y, unsigned int a, unsigned int b, unsigned int fill) ;

// 画三角形
void draw_triangle(unsigned int x1, unsigned int y1, unsigned int x2, unsigned int y2, unsigned int x3, unsigned int y3, unsigned int fill) ;

// 显示画布 
void showcanvas() ;

void clearScreen();

/

#endif

总结

        1、如果有不会写的功能可以问AI。AI太强大,写出的代码效率很高,思路清晰,就是有些算法看不懂。

        2、部分函数可能存在问题。

99e526d354e142d0ba18630f50b546d1.jpg

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值