74-UART-SPI-LCM_DMA_交替使用下载显示图片例程,STC8H8K64U实验箱演示程序, STC8H2K3
74-UART-SPI-LCM_DMA_交替使用下载显示图片例程,STC8H8K64U实验箱演示程序, STC8H2K32U, STC8H2K12U, STC8H主程序main.C代码如下(汇编版本在附件中):
/*---------------------------------------------------------------------*/
/* --- Web: www.STCAI.com ---------------------------------------------*/
/* --- BBS: www.STCAIMCU.com-----------------------------------------*/
/* 如果要在程序中使用此代码,请在程序中注明使用了STC的资料及程序 */
/*---------------------------------------------------------------------*/
/*************功能说明 **************
本例程基于STC8H为主控芯片的实验箱进行编写测试。
UART DMA + SPI DMA + LCM DMA驱动液晶屏程序
下载图片时通过串口(P3.0,P3.1)DMA接收图片数据,SPI DMA保存到Flash里。
显示时SPI DMA读取Flash图片数据,LCM DMA显示图片。
由于使用的SPI Flash一次最多只能写入256字节数据,UART接收SPI写入Flash的DMA数据长度设置256字节。
SPI读取Flash与LCM显示DMA的数据长度设置256字节。
发送DMA缓冲区与接收DMA缓冲区交替使用。
8bit I8080模式, P6口接数据线
LCD_RS = P4^5 //数据/命令切换
LCD_WR = P4^2 //写控制
LCD_RD = P4^4 //读控制
LCD_CS = P3^4 //片选
LCD_RESET = P4^3 //复位
SPI Flash 接口:
SPI_SS = P2^2;
SPI_MOSI = P2^3;
SPI_MISO = P2^4;
SPI_SCLK = P2^5;
UART 接口:
RX = P3^0
TX = P3^1
下载时, 选择时钟 35MHz (用户可自行修改频率).
******************************************/
#include "STC8H.h"
#include "system.h"
#include "spi_flash.h"
#include "uart.h"
#include "lcm.h"
#include "stdio.h"
#include "iap_eeprom.h"
#define Timer0_Reload (65536UL -(MAIN_Fosc / 1000)) //Timer 0 中断频率, 1000次/秒
#define KEY_TIMER 30 //按键持续检测时间(ms)
sbit KEY1 = P3 ^ 2;
sbit KEY2 = P3 ^ 3;
u16 Key1_cnt;
u16 Key2_cnt;
bit Key1_Flag;
bit Key2_Flag;
bit Key1_Short_Flag;
bit Key2_Short_Flag;
bit B_1ms; //1ms标志
bit Mode_Flag;
bit AutoDisplayFlag;
u32 Max_addr;
u16 MSecond;
void GPIO_Init(void);
void Timer0_Init(void);
void KeyScan(void);
void UART_SPI_DMA_BufSwitch(void);
void LCM_SPI_DMA_BufSwitch(void);
void main(void)
{
u8 temp;
P_SW2 |= 0x80;//扩展寄存器(XFR)访问使能
GPIO_Init();
Timer0_Init();
LCM_Config();
LCM_DMA_Config();
UART1_config(1);// 选择波特率, 2: 使用Timer2做波特率, 其它值: 使用Timer1做波特率.
// UART1_DMA_Config();
EA = 1;
SPI_init();
SPI_DMA_Config();
LCD_Init(); //LCM初始化
EEPROM_read_n(EE_ADDRESS,temp,4); //读出4字节
Max_addr = ((u32)temp << 24) | ((u32)temp << 16) | ((u32)temp << 8) | (u32)temp;
if(Max_addr == 0xffffffff)
{
Max_addr = 0;
}
while(1)
{
if(Mode_Flag == 0)
{
if(!SpiDmaFlag && !LcmDmaFlag && (lcdIndex > 0))
{
LCM_SPI_DMA_BufSwitch();
LcmDmaFlag = 1;
DMA_LCM_CR = 0xa0; //LCM DMA Write dat
Flash_addr += DMA_AMT_LEN;
SPI_Read_Nbytes(Flash_addr,DMA_AMT_LEN);
// printf("LCD index=%u\r\n",lcdIndex);
}
}
else if(Mode_Flag == 1)
{
if(!SpiDmaFlag && UartDmaRxFlag)
{
UartDmaRxFlag = 0;
UART_SPI_DMA_BufSwitch();
SPI_Write_Nbytes(Flash_addr,DMA_WR_LEN);
Flash_addr += DMA_WR_LEN;
DMA_UR1R_CR = 0xa0; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
}
}
if(B_1ms) //1ms到
{
B_1ms = 0;
KeyScan();
if(AutoDisplayFlag)
{
MSecond++;
if(MSecond >= 1000)
{
MSecond = 0;
Mode_Flag = 0;
if(Flash_addr >= Max_addr)
{
Flash_addr = 0;
DmaBufferSW = 0;
}
lcdIndex = DMA_S_TIMES;//600 * 256 = 320 * 240 * 2
LCD_Display();
SPI_DMA_Config();
LCM_DMA_Config();
SPI_Read_Nbytes(Flash_addr,DMA_AMT_LEN);
}
}
if(RX1_TimeOut > 0) //超时计数
{
if(--RX1_TimeOut == 0)
{
UART_SPI_DMA_BufSwitch();
SPI_Write_Nbytes(Flash_addr,DMA_UR1R_DONE);
Flash_addr += DMA_UR1R_DONE;
Max_addr = Flash_addr;
//关闭接收DMA,下次接收的数据重新存放在起始地址位置,否则下次接收数据继续往后面存放。
DMA_UR1R_CR = 0x00; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
printf("\r\nUART1 Timeout receive end!\r\n");//UART1发送一个字符串
temp = (u8)(Max_addr >> 24);
temp = (u8)(Max_addr >> 16);
temp = (u8)(Max_addr >> 8);
temp = (u8)Max_addr;
EEPROM_SectorErase(EE_ADDRESS); //擦除扇区
EEPROM_write_n(EE_ADDRESS,temp,4);
}
}
}
}
}
//========================================================================
// 函数: void UART_SPI_DMA_BufSwitch(void)
// 描述: UART与SPI的DMA缓冲区切换函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2022-8-26
// 备注:
//========================================================================
void UART_SPI_DMA_BufSwitch(void)
{
if(DmaBufferSW)
{
DmaBufferSW = 0;
DMA_UR1R_RXAH = (u8)((u16)&DmaBuffer1 >> 8);
DMA_UR1R_RXAL = (u8)((u16)&DmaBuffer1);
DMA_SPI_TXAH = (u8)((u16)&DmaBuffer2 >> 8); //SPI发送数据存储地址
DMA_SPI_TXAL = (u8)((u16)&DmaBuffer2);
}
else
{
DmaBufferSW = 1;
DMA_UR1R_RXAH = (u8)((u16)&DmaBuffer2 >> 8);
DMA_UR1R_RXAL = (u8)((u16)&DmaBuffer2);
DMA_SPI_TXAH = (u8)((u16)&DmaBuffer1 >> 8); //SPI发送数据存储地址
DMA_SPI_TXAL = (u8)((u16)&DmaBuffer1);
}
}
//========================================================================
// 函数: void LCM_SPI_DMA_BufSwitch(void)
// 描述: LCM与SPI的DMA缓冲区切换函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2022-8-26
// 备注:
//========================================================================
void LCM_SPI_DMA_BufSwitch(void)
{
if(DmaBufferSW)
{
DmaBufferSW = 0;
DMA_LCM_TXAH = (u8)((u16)&DmaBuffer2 >> 8);
DMA_LCM_TXAL = (u8)((u16)&DmaBuffer2);
DMA_SPI_RXAH = (u8)((u16)&DmaBuffer1 >> 8); //SPI接收数据存储地址
DMA_SPI_RXAL = (u8)((u16)&DmaBuffer1);
}
else
{
DmaBufferSW = 1;
DMA_LCM_TXAH = (u8)((u16)&DmaBuffer1 >> 8);
DMA_LCM_TXAL = (u8)((u16)&DmaBuffer1);
DMA_SPI_RXAH = (u8)((u16)&DmaBuffer2 >> 8); //SPI接收数据存储地址
DMA_SPI_RXAL = (u8)((u16)&DmaBuffer2);
}
}
//========================================================================
// 函数: void delay_ms(u16 ms)
// 描述: 延时函数。
// 参数: ms,要延时的ms数, 自动适应主时钟.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void delay_ms(u16 ms)
{
u16 i;
do{
i = MAIN_Fosc / 10000;
while(--i);
}while(--ms);
}
//========================================================================
// 函数: void GPIO_Init(void)
// 描述: IO口设置函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2022-8-24
// 备注:
//========================================================================
void GPIO_Init(void)
{
//漏极开路+上拉电阻模式信号上升速度慢,需要减速才能正常通信,影响显示速度
// P0M1 = 0x30; P0M0 = 0x30; //设置P0.4、P0.5为漏极开路(实验箱加了上拉电阻到3.3V)
// P1M1 = 0x32; P1M0 = 0x32; //设置P1.1、P1.4、P1.5为漏极开路(实验箱加了上拉电阻到3.3V), P1.1在PWM当DAC电路通过电阻串联到P2.3
// P2M1 = 0x3c; P2M0 = 0x3c; //设置P2.2~P2.5为漏极开路(实验箱加了上拉电阻到3.3V)
// P3M1 = 0x50; P3M0 = 0x50; //设置P3.4、P3.6为漏极开路(实验箱加了上拉电阻到3.3V)
// P4M1 = 0x3c; P4M0 = 0x3c; //设置P4.2~P4.5为漏极开路(实验箱加了上拉电阻到3.3V)
// P5M1 = 0x0c; P5M0 = 0x0c; //设置P5.2、P5.3为漏极开路(实验箱加了上拉电阻到3.3V)
// P6M1 = 0xff; P6M0 = 0xff; //设置为漏极开路(实验箱加了上拉电阻到3.3V)
// P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
P0M1 = 0x00; P0M0 = 0x00; //设置为准双向口
P1M1 = 0x00; P1M0 = 0x00; //设置为准双向口
P2M1 = 0x00; P2M0 = 0x00; //设置为准双向口
P3M1 = 0x00; P3M0 = 0x00; //设置为准双向口
P4M1 = 0x00; P4M0 = 0x00; //设置为准双向口
P5M1 = 0x00; P5M0 = 0x00; //设置为准双向口
P6M1 = 0x00; P6M0 = 0x00; //设置为准双向口
P7M1 = 0x00; P7M0 = 0x00; //设置为准双向口
//P6口设置成推挽输出
P6M0=0xff;
P6M1=0x00;
//P3.4口设置成推挽输出
P3M0=0x10;
P3M1=0x00;
//P4.2,P4.3,P4.4,P4.5口设置成推挽输出
P4M0=0x3c;
P4M1=0x00;
}
//========================================================================
// 函数: void Timer0_Init(void)
// 描述: 定时器0设置函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2022-8-24
// 备注:
//========================================================================
void Timer0_Init(void)
{
AUXR = 0x80; //Timer0 set as 1T, 16 bits timer auto-reload,
TH0 = (u8)(Timer0_Reload / 256);
TL0 = (u8)(Timer0_Reload % 256);
ET0 = 1; //Timer0 interrupt enable
TR0 = 1; //Tiner0 run
}
//========================================================================
// 函数: void timer0_Interrupt(void) interrupt 1
// 描述: 定时器0中断函数。
// 参数: nine.
// 返回: none.
// 版本: VER1.0
// 日期: 2014-11-28
// 备注:
//========================================================================
void timer0_Interrupt(void) interrupt 1
{
B_1ms = 1; //1ms标志
}
//========================================================================
// 函数: void KeyScan(void)
// 描述: 按键扫描函数。
// 参数: none.
// 返回: none.
// 版本: VER1.0
// 日期: 2013-4-1
// 备注:
//========================================================================
void KeyScan(void)
{
if(!KEY1)
{
if(!Key1_Flag)
{
Key1_cnt++;
if(Key1_cnt >= 1000) //长按1s
{
Key1_Short_Flag = 0; //清除短按标志
Key1_Flag = 1; //设置按键状态,防止重复触发
printf("LCM auto display...\r\n");
DMA_SPI_CR = 0x00; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
DMA_SPI_STA = 0x00;
DMA_UR1R_CR = 0x00; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
DMA_UR1R_STA = 0x00;
AutoDisplayFlag = 1;
Flash_addr = 0;
DmaBufferSW = 0;
lcdIndex = DMA_S_TIMES;//600 * 256 = 320 * 240 * 2
LCD_Display();
// printf("Start LCD display...\r\n");
SPI_DMA_Config();
LCM_DMA_Config();
SPI_Read_Nbytes(Flash_addr,DMA_AMT_LEN);
}
else if(Key1_cnt >= KEY_TIMER) //30ms防抖
{
Key1_Short_Flag = 1; //设置短按标志
}
}
}
else
{
if(Key1_Short_Flag) //判断是否短按
{
Key1_Short_Flag = 0; //清除短按标志
DMA_SPI_CR = 0x00; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
DMA_SPI_STA = 0x00;
DMA_UR1R_CR = 0x00; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
DMA_UR1R_STA = 0x00;
Mode_Flag = 0;
AutoDisplayFlag = 0;
printf("Max_addr = %lu, Flash_addr = %lu\r\n",Max_addr,Flash_addr);
if(Flash_addr >= Max_addr)
{
Flash_addr = 0;
DmaBufferSW = 0;
}
lcdIndex = DMA_S_TIMES;//600 * 256 = 320 * 240 * 2
LCD_Display();
// printf("Start LCD display...\r\n");
SPI_DMA_Config();
LCM_DMA_Config();
SPI_Read_Nbytes(Flash_addr,DMA_AMT_LEN);
}
Key1_cnt = 0;
Key1_Flag = 0;
}
if(!KEY2)
{
if(!Key2_Flag)
{
Key2_cnt++;
if(Key2_cnt >= 1000) //长按1s
{
Key2_Short_Flag = 0; //清除短按标志
Key2_Flag = 1; //设置按键状态,防止重复触发
DMA_LCM_CR = 0x00;
DMA_LCM_STA = 0x00;
DMA_SPI_CR = 0x00; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
DMA_SPI_STA = 0x00;
DMA_UR1R_CR = 0x00; //bit7 1:使能 UART1_DMA, bit5 1:开始 UART1_DMA 自动接收, bit0 1:清除 FIFO
DMA_UR1R_STA = 0x00;
Mode_Flag = 1;
DmaBufferSW = 0;
Flash_addr = 0;
Max_addr = 0;
printf("Start Flash Chip Erase...\r\n");
FlashChipErase();
printf("Flash Chip Erase OK!\r\n");
}
else if(Key2_cnt >= KEY_TIMER) //30ms防抖
{
Key2_Short_Flag = 1; //设置短按标志
}
}
}
else
{
if(Key2_Short_Flag) //判断是否短按
{
Key2_Short_Flag = 0; //清除短按标志
Mode_Flag = 1;
Flash_addr = Max_addr;//继续添加图片
printf("Ready to receive data...\r\n");
UART1_DMA_Config();
SPI_DMA_Config();
}
Key2_cnt = 0;
Key2_Flag = 0; //按键释放
}
}
页:
[1]