/**************************LED驱动函数*********/
#include "stm32f10x.h" // Device header
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "Delay.h"
#include "LED_Driver.h"
#include "stm32f10x_it.h"
#include "Handlers.h"
#include "hanzi.h"
/*
屏幕大小为16*64,0-15行,0-63列
一、屏幕数据流向,箭头方向的左下角,到右上角
二、点阵字模要求
1,点阵字模软件:PCtoLCD2002
2,字模选项
(1)点阵格式:阴码
(2)取模方式:逐行式
(3)每行显示数据:点阵16,索引16
(4)取模走向:逆向
(5)输出进制:16进制
(6)格式:C51
*/
#define HC245_A_PORT GPIOA
#define HC245_B_PORT GPIOB
#define HC245_C_PORT GPIOC
/*
HC245
DIR接5V OE接GND A->B
HUB12
第一列引脚,从上到下为OE,N,N,N,N,N,N,N
第二列引脚,从上到下为A,B,C,SCK,LAT,R,G,D
*/
#define A_A1_PA0 GPIO_Pin_0
#define B_A2_PA1 GPIO_Pin_1
#define C_A3_PB5 GPIO_Pin_5
#define D_A4_PB4 GPIO_Pin_4
#define OE_A5_PA8 GPIO_Pin_8
#define LAT_A6_PC8 GPIO_Pin_8
#define SCK_A7_PC9 GPIO_Pin_9
#define R_A15_PB8 GPIO_Pin_8
#define G_A16_PC0 GPIO_Pin_0
void HC245_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin=A_A1_PA0|B_A2_PA1|OE_A5_PA8;
GPIO_Init(HC245_A_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=C_A3_PB5|D_A4_PB4|R_A15_PB8;
GPIO_Init(HC245_B_PORT,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=LAT_A6_PC8|SCK_A7_PC9|G_A16_PC0;
GPIO_Init(HC245_C_PORT,&GPIO_InitStructure);
}
// 数据线 - 红色 (R -> PB8)
#define HIGH_HUB12_DR (GPIOB->BSRR = GPIO_Pin_8)
#define LOW_HUB12_DR (GPIOB->BRR = GPIO_Pin_8)
// 数据线 - 绿色 (G -> PC0)
#define HIGH_HUB12_DG (GPIOC->BSRR = GPIO_Pin_0)
#define LOW_HUB12_DG (GPIOC->BRR = GPIO_Pin_0)
// 时钟线 (SCK / SH_CP -> PC9)
#define HIGH_HUB12_CLK (GPIOC->BSRR = GPIO_Pin_9)
#define LOW_HUB12_CLK (GPIOC->BRR = GPIO_Pin_9)
// 锁存线 (LAT / ST_CP -> PC8)
#define HIGH_HUB12_LAT (GPIOC->BSRR = GPIO_Pin_8)
#define LOW_HUB12_LAT (GPIOC->BRR = GPIO_Pin_8)
// 输出使能 (OE -> PA8, 低电平有效)
#define HIGH_HUB12_OE (GPIOA->BSRR = GPIO_Pin_8)
#define LOW_HUB12_OE (GPIOA->BRR = GPIO_Pin_8)
// 行地址线 A (A -> PA0)
#define HIGH_HUB12_A (GPIOA->BSRR = GPIO_Pin_0)
#define LOW_HUB12_A (GPIOA->BRR = GPIO_Pin_0)
// 行地址线 B (B -> PA1)
#define HIGH_HUB12_B (GPIOA->BSRR = GPIO_Pin_1)
#define LOW_HUB12_B (GPIOA->BRR = GPIO_Pin_1)
// 行地址线 C (C -> PB5)
#define HIGH_HUB12_C (GPIOB->BSRR = GPIO_Pin_5)
#define LOW_HUB12_C (GPIOB->BRR = GPIO_Pin_5)
// 行地址线 D (D -> PB4)
#define HIGH_HUB12_D (GPIOB->BSRR = GPIO_Pin_4)
#define LOW_HUB12_D (GPIOB->BRR = GPIO_Pin_4)
/* 显示汉字总数 */
#define WORD_NUM 4
/* 每行显示的字节数 */
#define SCAN_NUM (8 * WORD_NUM)
u8 Chinese[4][32] =
{
{
0x00,0x01,0x00,0x01,0x3F,0x01,0x20,0x3F,0xA0,0x20,0x92,0x10,0x54,0x02,0x28,0x02,
0x08,0x02,0x14,0x05,0x24,0x05,0xA2,0x08,0x81,0x08,0x40,0x10,0x20,0x20,0x10,0x40,
},
{
0x00,0x00,0x04,0x01,0xC8,0x3C,0x48,0x24,0x40,0x24,0x40,0x24,0x4F,0x24,0x48,0x24,
0x48,0x24,0x48,0x2D,0xC8,0x14,0x48,0x04,0x08,0x04,0x14,0x04,0xE2,0x7F,0x00,0x00,
},
{
0x80,0x00,0x84,0x10,0x88,0x10,0x90,0x08,0x90,0x04,0x80,0x00,0xFF,0x7F,0x20,0x02,
0x20,0x02,0x20,0x02,0x20,0x02,0x10,0x42,0x10,0x42,0x08,0x42,0x04,0x7C,0x03,0x00,
},
{
0x10,0x01,0x10,0x01,0x10,0x01,0x92,0x7F,0x92,0x02,0x52,0x04,0x32,0x04,0x12,0x00,
0x92,0x3F,0x92,0x24,0x92,0x24,0x92,0x24,0x92,0x24,0x90,0x3F,0x90,0x20,0x10,0x00,
},
};
uint8_t dispram[128] = {0};
uint8_t copy_dispram[128]={0};
void hub12DataSerialInput(uint8_t data){
uint16_t i;
for( i = 0; i < 8; i++){
if(data & 0x80){
LOW_HUB12_DR;
}else{
HIGH_HUB12_DR;
}
Delay_us(1);
LOW_HUB12_CLK;
Delay_us(1);
HIGH_HUB12_CLK;
Delay_us(1);
data = data << 1;
}
}
// 行选择 (1/4扫描)
void hub12SelectRows(uint8_t rows){
LOW_HUB12_C;
LOW_HUB12_D;
switch(rows){
case 0:
LOW_HUB12_A;
LOW_HUB12_B;
break;
case 1:
HIGH_HUB12_A;
LOW_HUB12_B;
break;
case 2:
LOW_HUB12_A;
HIGH_HUB12_B;
break;
case 3:
HIGH_HUB12_A;
HIGH_HUB12_B;
break;
default:
break;
}
}
// 行选择 (1/4扫描)
void hub12Display(uint16_t bright,uint8_t *buffer)
{
for(u8 s=0; s<4; s++){ // 4个行组(1/4扫描)
Delay_us(2);
HIGH_HUB12_OE;
Delay_us(1);
hub12SelectRows(s);
Delay_us(2);
LOW_HUB12_LAT;
Delay_us(2);
for(int i=0; i<SCAN_NUM; i++) {
hub12DataSerialInput(buffer[s*SCAN_NUM + i]); //128字节
}
HIGH_HUB12_LAT;
Delay_us(2);
LOW_HUB12_OE;
Delay_us(bright);
HIGH_HUB12_OE;
}
}
//高低字节交换,0b10110000 → 0b00001101
u8 SwapByte(u8 data)
{
data=(data<<4)|(data>>4);
data=((data<<2)&0xcc)|((data>>2)&0x33);
data=((data<<1)&0xaa)|((data>>1)&0x55);
return data;
}
void WriteScreen(u8 locatin, u8 *text)
{
u8 i; // 原始的扫描行组
u8 j; // 显示缓冲区的标号
u8 k;
u8 buffer[32];
const u8 row_map[4] = {1,2,3, 0}; //行扫描修正
/* 字模处理 */
for(k = 0; k < 32; k++) buffer[k] = text[31 - k]; //从左到右,从上到下依次显示
for(k = 0; k < 32; k++) buffer[k] =SwapByte(buffer[k]);
/* 写缓冲区 */
for(i = 0; i < 4; i++) // 4组扫描行 (i=0,1,2,3 对应 4/1,4/2,4/3,4/4)
{
// 通过查找表,获取用于行修正计算的 "new_i"
u8 new_i = row_map[i];
for(j = (SCAN_NUM * i); j < SCAN_NUM * (i + 1); j++)
{
if((j >= ((SCAN_NUM * i) + 8 * locatin)) && (j <= ((SCAN_NUM * i + 3) + 8 * locatin)))//0-3列
{
// 使用 new_i 来计算行修正项,但 j 的范围仍基于原始的 i
dispram[j] = buffer[(7 - 2 * new_i) + 8 * (j - 8 * locatin - SCAN_NUM * i)]; //右边字节
}
if((j >= ((SCAN_NUM * i + 4) + 8 * locatin)) && (j <= ((SCAN_NUM * i + 7) + 8 * locatin)))//4-7列
{
dispram[j] = buffer[(6 - 2 * new_i) + 8 * (j - 8 * locatin - SCAN_NUM * i - 4)]; //左边字节
}
}
}
}
//静态显示汉字
void StaticDisplay(uint8_t font[4][32])
{
memset(dispram, 0, sizeof(dispram)); // 清空显存
//locatin,0-3,表示第几个汉字的位置
for(u8 locatin=0;locatin<4;locatin++)
{
WriteScreen(locatin, font[locatin]);
}
}
u8 display_buffer[16][10]; // 扩展为10字节,容纳5个汉字
u8 hanzi_data[4][32]; // 4个汉字的缓冲区
// 初始化显示缓冲区
void InitDisplayBuffer() {
memset(display_buffer, 0, sizeof(display_buffer));
// 初始化前4个汉字
for(u8 i = 0; i < 4; i++) {
for(u8 row = 0; row < 16; row++) {
display_buffer[row][i*2] = Chinese[i][row*2];
display_buffer[row][i*2+1] = Chinese[i][row*2+1];
}
}
}
void ScrollTextLeft(u8 Chinese[][32], u8 hanzi_num) {
static u8 start_index = 0;
static u8 shift_count = 0;
u8 next_index = 4 % hanzi_num; // 下一个汉字索引
// 移动一列
for (u8 row = 0; row < 16; row++) {
// 将当前字节左移1位,然后从下一个字节的最高位取1位,放到当前字节的最低位
for (u8 col = 0; col < 9; col++) {
display_buffer[row][col] = (display_buffer[row][col] << 1) |
((display_buffer[row][col+1] & 0x80) ? 1 : 0);
}
//将第一个字节左移8位到高8位,将第二个字节放到低8位
u16 row_data = (Chinese[next_index][row*2] << 8) | Chinese[next_index][row*2+1];
//从16位数据中按列提取相应的位
u8 bit_value = (row_data >> (15 - shift_count)) & 0x01;
//将取到的位放到显示缓冲区最右侧字节的最低位
display_buffer[row][9] = (display_buffer[row][9] << 1) | bit_value;
}
// 每次循环提取一个完整的汉字送到 WriteScreen 函数进行显示处理。
for (u8 i = 0; i < 4; i++) {
for (u8 row = 0; row < 16; row++) {
hanzi_data[i][row*2] = display_buffer[row][i*2];
hanzi_data[i][row*2+1] = display_buffer[row][i*2+1];
}
WriteScreen(i, hanzi_data[i]);
}
__disable_irq();
memset(copy_dispram, 0, sizeof(copy_dispram));
memcpy(copy_dispram, dispram, sizeof(dispram));
__enable_irq();
// 更新计数和索引
shift_count++;
if (shift_count >= 16) {
shift_count = 0;
start_index = (start_index + 1) % hanzi_num;
next_index = (start_index + 4) % hanzi_num;
// 将下一个汉字加载到缓冲区
for(u8 row = 0; row < 16; row++) {
display_buffer[row][8] = Chinese[next_index][row*2];
display_buffer[row][9] = Chinese[next_index][row*2+1];
}
}
Delay_ms(30);
}
/***********************main函数**************************/
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "Serial.h"
#include "LED_Driver.h"
#include "ChineseFont.h"
#include "flash.h"
#include "hanzi.h"
volatile uint8_t TYPE=2;
//TYPE=1静态显示
void Static_Type(void)
{
if(TYPE)
{
StaticDisplay(Chinese);
}
}
int main(void)
{
Serial_Init();
HC245_Init();
FLASH_Init();
printf("init\n");
//TYPE=1静态显示
Static_Type();
InitDisplayBuffer();
while (1) {
hub12Display(300,copy_dispram);
switch(TYPE)
{
case 2:
ScrollTextLeft(Chinese,4);
//Delay_ms(30);
break;
case 3:
break;
}
}
}
当TYPE=2的时候,ScrollTextLeft循环,然后循环执行WriteScreen(i, hanzi_data);计算出dispram,所以dispram在不断地被写入,数据在一直更新,所以再调用hub12Display写LED屏的时候,屏幕上面有鬼影,重影。
在void ScrollTextLeft(u8 Chinese[][32], u8 hanzi_num)中,添加了双重缓存区,
__disable_irq();
memset(copy_dispram, 0, sizeof(copy_dispram));
memcpy(copy_dispram, dispram, sizeof(dispram));
__enable_irq();,也没有用,各位大佬,有没有什么办法?
相似问题