找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1334|回复: 2
收起左侧

stc15f2k60s2单片机利用串口传输字模存储到eeprom并进行点阵显示

[复制链接]
ID:1135238 发表于 2024-11-1 13:57 | 显示全部楼层 |阅读模式
想做一个电子名牌,上位机端大致已经弄好,现在单片机端程序还有问题。程序首先读取eeprom的数据存储到buffer数组中,主函数初始化串口,根据标志位决定是否擦除扇区,并将通过串口接受的数据存入eeprom,实质就是看串口有无数据进来,没有就显示原本存储的数据,标志位是一个全局变量,由中断程序控制值。代码我贴在下面,目前就是使用isp打开串口后,显示会短暂消失一下,进入了while(1)循环,发送数据不起作用,有没有大神解答一下问题。
单片机源程序如下:
#include <stc15f2k60s2.h>
#include "eeprom.h"
#define uchar unsigned char
#define uint unsigned int

/* 点阵显示宏定义 */
sbit KEY = P3 ^ 2;
sbit T_STR = P3 ^ 7;    // 锁存引脚
sbit T_IO  = P1 ^ 4;    // 数据引脚
sbit T_CLK = P3 ^ 6;    // 时钟引脚
sbit T_OE  = P3 ^ 5;

uchar row = 0, col;
uchar xdata receivedData[16][8];
uchar xdata buffer[256];
uint flag = 0;
uint count = 0;
uint eepromAddress = 0x0000;

void UartInit(void) {
        PCON &= 0x7F; // 波特率不倍速
        SCON = 0x50; // 8位数据,可变波特率
        AUXR |= 0x40; // 定时器1时钟为Fosc
        AUXR &= 0xFE; // 串口1选择定时器1为波特率发生器
        TMOD &= 0x0F; // 清除定时器1模式位
        TMOD |= 0x20; // 设定定时器1为8位自动重装方式
        TL1 = 0xDC; // 设定初值
        TH1 = 0xDC; // 设定定时器重装初值
        ET1 = 0; // 禁止定时器1中断
        TR1 = 1; // 启动定时器1
        ES = 1; // 开启串口中断允许
        EA = 1; // 开启全局中断允许
}

unsigned char AsciiToHex(unsigned char ascii) {
        if (ascii >= '0' && ascii <= '9') {
                return ascii - '0';   // 将字符 '0'-'9' 转换为 0x0-0x9
        } else if (ascii >= 'A' && ascii <= 'F') {
                return ascii - 'A' + 0xA;   // 将字符 'A'-'F' 转换为 0xA-0xF
        } else {
                return 0x00;  // 如果不在范围内,返回默认值 0x00
        }
}

void ReadFromEeprom(uint address) {
        uint i, j;
        for (i = 0; i < 16; i++) { // 遍历16行
                for (j = 0; j < 8; j++) { // 每行8个字节
                        unsigned char highByteAscii = IapReadByte(address);     // 读取高位 ASCII
                        unsigned char lowByteAscii = IapReadByte(address + 1);  // 读取低位 ASCII
                        // 转换 ASCII 值为十六进制数字
                        unsigned char highByte = AsciiToHex(highByteAscii);
                        unsigned char lowByte = AsciiToHex(lowByteAscii);
                        // 合并高、低位为一个8位的十六进制数
                        receivedData[ i][j] = (highByte << 4) | (lowByte & 0x0F);
                        address += 2;  // 每次读取后地址增加2,以读取下一个字节对
                }
        }
}

void WriteToEeprom(uint address, uchar data1) {
        IapProgramByte(address, data1); // 使用定义好的函数写入EEPROM
}

void Delay(unsigned int t) {
        while (--t);
}

void InputByte(unsigned char dat) {
        unsigned char i;
        for (i = 0; i < 8; i++) {
                T_IO = !(dat & 0x01);
                dat >>= 1;
                T_CLK = 0;
                T_CLK = 1;
        }
}

/*void SendString(uchar *str) {
        while (*str) {
                SBUF = *str++;
                while (!TI);
                TI = 0;
        }
} */

void main(void) {
        uint i,j;
        ReadFromEeprom(eepromAddress);
        eepromAddress = 0x0000;
        
        
        UartInit();
        
        //SendString("2"); // 发送 "2" 表示初始化完成

        P3M0 = 0xff; // 推挽
        P1M0 = 0xff;
        P3M1 = 0;
        P1M1 = 0;
        AUXR |= 0x80;

        while(1) {
                //SendString("x");
                if(flag == 1) {
                        ES = 0;
                        //SendString("3"); // 当接收到完整数据包后发送 "3"
                        IapEraseSector(0x0000);
                        for(i = 0; i < 256; i++) {
                                WriteToEeprom(eepromAddress++, buffer[ i]);
                        }
                        eepromAddress = 0x0000;
                        ReadFromEeprom(eepromAddress);
                        for(i=0;i<16;i++)
                        {
                                for(j=0;j<8;j++)
                                {
                                        SBUF = receivedData[ i][j];
                                        while(!TI);
                                        TI = 0;
                                }
                        }
                        eepromAddress = 0x0000;
                        flag = 0;
                        ES = 1;
                }
        

                Delay(1);
                T_OE = 0;
                T_STR = 0; // 锁存无效
                for (col = 0; col < 8; col++) {
                        InputByte(receivedData[row][col]); // 输出到 595
                }
                P1 = row; // 用 P1 口的前 4 位控制 16 行
                T_STR = 1; // 锁存有效,此时一行的数据显示到屏上
                T_OE = 1;
                row++;
                if (row == 16) {
                        row = 0;
                }
        }
}

void ser() interrupt 4 {
        uchar receivedByte;
        if(RI) {
                receivedByte = SBUF;
                RI = 0; // 清除接收标志位
                buffer[count++] = receivedByte;
                //SendString("6");
                if (count == 256) {
                        flag = 1;
                        count = 0;               
                        //SendString("1");
                }
        }
        if(TI) {

                TI = 0;        
        }
}
回复

使用道具 举报

ID:1133081 发表于 2024-11-1 21:58 | 显示全部楼层
欲用串口正确传输数据串通常需要自定义一个通讯协议,协议内容通常包括1~2个字节的数据头标识、1~2个字节数据长度的数据、若干字节的有效数据、验证码以及数据尾(结束标识)等。上下位机按此通讯协议发送、接收和解析,否则无法保证通讯质量。
回复

使用道具 举报

ID:879348 发表于 2024-11-4 10:25 | 显示全部楼层
如果你不需要再次改变,不需要这么复杂,图片直接做成bin文件,烧录的时候和程序一起烧录
回复

使用道具 举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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