- 打卡等级:以坛为家II
- 打卡总天数:494
- 最近打卡:2025-05-02 09:16:59
荣誉版主
- 积分
- 3480
|
发表于 2024-9-27 12:03:17
|
显示全部楼层
贴一下主文件
//=================================================================================================
// 文件名称: Main.C
// 功能说明: 测试液晶屏模块驱动函数 2.4寸彩色显示屏 240*320 8位并行口模式+ 测试通信以及W25Q40读写
// 基于电路: STC32G12K128 实验箱V9.62
// 整理改编: 浦晓明(浦江一水) 2024-09-14
// 实验内容: 实验全屏彩色图片显示
//**************************************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "STC32G.H"
#include "STC32G_SYS.H"
#include "STC32G_UART2.H"
#include "LCD9341.H"
#include "KEY8.H"
#include "W25Q40.H" //存储512K
//全局变量说明
unsigned char k; //键值
unsigned char m,n; //菜单项
char S[80]; //显示缓存
unsigned long ADDR = 0; //0x25800/0x4B000
unsigned long Length=153600;
u16 W25Q40_ID; //设备ID
u32 T_Addr; //目标地址
u8 R_Buf[256]; //读取数据缓存
extern u8 xdata F_Buf[4096]; //扇区缓存
//菜单项目定义...
char * MN[6]={ "0.PC<->W25Qx", "1.FlashW25Qx","2.Read W25Qx","3.Del_Sector","4.Del_Block ","5.Disp PICx ", };
//函数说明(凡是排列在main()之后的函数须先说明一下)
void PCRW_W25Q(void); //PC机通信实验W25Q读写
void FlashW25Q(void); //PC机通信刷新扇区数据
void Read_W25Q(void); //读出扇区数据-页256字节
void DelSector(void); //删除指定扇区4096字节
void DelBlock(void); //删除块数据(64K)
void Disp_PIC(void); //显示图片
//=============================================================================
// 输入整型数 (10进制数显示)
//=============================================================================
unsigned long InputI(unsigned int X,unsigned int Y,char * I)
{ unsigned char set=1;
unsigned int i=0,Val=0,l;
l=strlen(I)-1;
while(set)
{ LCD_Str12(X,Y,I,7,0);
LCD_A12(X+i*8,Y,I[i],14,4);
k=0;k=GETCH();
switch(k)
{ case K40 : I[i]=I[i]<0x39? I[i]+1:0x30; break;
case K50 : I[i]=I[i]>0x30? I[i]-1:0x39; break;
case K60 : i=i<l?i+1:0; break;
case K61 : i=i>0?i-1:l; break;
case K70 : LCD_Str12(X,Y,I,15,0); set=0; break;
} if(i>l)i=0;
}
return(atol(I));
}
unsigned long Adr=0;
//=============================================================================
// 输入存储器入口地址 (16进制数显示)
//=============================================================================
unsigned long InputAdr(unsigned int X,unsigned int Y,char * F)
{ unsigned char set=1;
unsigned int i=0,val,l;
l=strlen(F)-1;
while(set)
{ LCD_Str12(X,Y,F,7,0);
LCD_A12(X+i*8,Y,F[i],14,4);
k=0;k=GETCH();
switch(k)
{ case K40 : F[i]=F[i]<0x46? F[i]+1:0x30; if(F[i]==0x3A)F[i]=0x41; break;
case K50 : F[i]=F[i]>0x30? F[i]-1:0x46; if(F[i]==0x40)F[i]=0x39; break;
case K60 : i=i<l?i+1:0; break; //短按
case K61 : i=i>0?i-1:l; break; //长按
case K70 : LCD_Str12(X,Y,F,15,0); set=0; break;
} if(i>l)i=0;
} Adr=0;
for(i=0;i<=l;i++)
{ val=F[i]<0x3A?F[i]-48:F[i]-55;
Adr=16*Adr+val;
}
return(Adr);
}
//=============================================================================
// 主函数
//=============================================================================
void main(void)
{ u16 i;
u8 disp=1;
SYS_Init(); //系统初始化(35MHz)
KEY8_Init(); //键盘初始化
LCD_Init(); //液晶屏初始化
//LCD_SetDIR(0); //原显示方向(纵向屏)
LCD_SetDIR(3); //调整显示方向(横屏)
LCD_CLS(0); //清屏
W25Q40_Init();
W25Q40_ID=W25Q40_ReadID(); //读取ID(验证设备是否存在)
UART2_Init(1,1,115200); //IO切换1,模式1,波特率115200
UART2_SendStr("STC32G12K128_UART2_OK!\r\n");
printf("Printf()_UART2_OK!\r\n");
m=0;
while(1)
{
if(disp)
{ disp=0;
LCD_CLS(0); //清全屏
LCD_CLSA(0,0,319,22,1);//局部清屏
LCD_Str12(8,2,(char *)"Test TFT9341 W25Q40...",15,1);
LCD_CLSA(0,220,319,20,7);
for(i=0;i<6;i++) //显示主菜单项
{ if(m==i)LCD_Str12(10,30+20*i,(char *)MN[i],14,4);
else LCD_Str12(10,30+20*i,(char *)MN[i],15,0);
} LCD_Str12(10,222,"KEY=00",0,7); //显示按键值
}
k=0;k=GETCH(); //RDKEY();
if(k!=0)
{ sprintf(S,"KEY=%02X",k);
LCD_Str12(10,222,S,0,7);
switch(k)
{ case K40: LCD_Str12(10,30+20*m,(char *)MN[m],15,0);
m=m>0?m-1:5;
LCD_Str12(10,30+20*m,(char *)MN[m],14,4); break;
case K50: LCD_Str12(10,30+20*m,(char *)MN[m],15,0);
m=m<5?m+1:0;
LCD_Str12(10,30+20*m,(char *)MN[m],14,4); break;
case K60: break;
case K70: switch(m)
{ case 0: PCRW_W25Q(); disp=1; break; //实验与PC机通讯读写W25Q
case 1: FlashW25Q(); disp=1; break; //与PC机通讯刷新扇区数据(图片文件)
case 2: Read_W25Q(); disp=1; break; //读取W25Q扇区数据显示
case 3: DelSector(); disp=1; break; //删除W25Q指定扇区数据4096字节
case 4: DelBlock(); disp=1; break; //删除W25Q指定块区数据64K字节
case 5: Disp_PIC(); disp=1; break; //实验显示图片
}
break;
}
}
delay_ms(20); //延时
}
}
//PC机读写W25Q40(512K存储器)
void PCRW_W25Q(void)
{ unsigned char run=1,ts=1,ch,n;
u16 i,len;
LCD_CLSA(0,25,160,150,0);
LCD_Str12(10, 30,(char *)"PC<==>UART2+W25Q40 Read & Write...",10,0);
LCD_Str12(10,222,(char *)"Press K7 return...",0,7);
while(run)
{ k=0;k=RDKEY();
if(k==K70)run=0;
if(ts)
{ //实验操作提示...
printf("\r\n** STC32G单片机对外部Flash_W25Q40读写实验(主频35MHz) **\r\n");
printf("- 实验箱_USART2(RS232)串口连接PC机串口.波特率115200,8,1,N\r\n");
printf("- PC机使用串口助手,串口命令例\xfd举如下:(无需回车换行)\r\n");
printf("E 0x000020 --> 删除\xfd字节地址0x000020所在扇区.\r\n");
printf("W 0x000020 ABCDE12345 --> 写入地址0x000020字符串ABCDE12345\r\n");
printf("R 0x000020 10 --> 读出地址0x000020指定长度字节.\r\n");
printf("Q 0x000000 --> 返回主菜单...\r\n");
printf("读写地址范围: 0x000000 -- 0x07FFFF (512K)\r\n\r\n");
ts=0;
}
delay_ms(10);
if(RX2_Cnt>=10) //串口2收到指令信息...
{ for(i=0;i<8;i++)
{ if((RX2_Buf[i] >= 'a') && (RX2_Buf[i] <= 'z'))RX2_Buf[i] -= 0x20; } //小写转大写
if(((RX2_Buf[0]=='E')||(RX2_Buf[0]=='W')||(RX2_Buf[0]=='R')||(RX2_Buf[0]=='Q'))&&(RX2_Buf[1]==' '))
{ //解析地址...
ch=RX2_Buf[4]-0x30; if(ch>9)ch=ch-0x07; T_Addr=(u32)ch;
ch=RX2_Buf[5]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
ch=RX2_Buf[6]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
ch=RX2_Buf[7]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
ch=RX2_Buf[8]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
ch=RX2_Buf[9]-0x30; if(ch>9)ch=ch-0x07; T_Addr=16*T_Addr+(u32)ch;
//解析指令
switch(RX2_Buf[0])
{ case 'E': W25Q40_SectorErase(T_Addr);
printf("OK! Sector Erase.\r\n");
break;
case 'W': n=RX2_Cnt-11; //取指令数据长度
W25Q40_Write(T_Addr,RX2_Buf+11,n);
printf("OK! Write %2d Byte.\r\n",n);
break;
case 'R': n=RX2_Cnt-11; len=0; //取指令数据长度
for(i=0;i<n;i++) //取需要读取的数据长度
{ ch=RX2_Buf[11+i];
if((ch>='0')&&(ch<='9'))len=10*len+RX2_Buf[11+i]-'0';
else break;
}
if(len>256)len=256;
W25Q40_Read(T_Addr,R_Buf,len);
printf("OK! Read out %3d Bytes:\r\n",len);
for(i=0;i<len;i++)UART2_SendChar(R_Buf[i]);
UART2_SendChar(0x0D); UART2_SendChar(0x0A);
break;
case 'Q': n=RX2_Cnt-11; len=0; run=0; break;
}
} else { printf("指令错误!!\r\n");ts=1; }
RX2_Cnt=0;RX2_Buf[0]=0; //计数清零
}
}
}
// 刷新存储器...
void FlashW25Q(void)
{ unsigned int Dh,Dl,Cnt=0;
unsigned char wait=1;
LCD_CLSA(0,25,160,150,0);
LCD_Str12(10,30,(char *)"Address=0x00000 (<=0x7FF00)",10,0);
Dh=ADDR / 65536; Dl=ADDR % 65536;
sprintf(S,"%1X%04X",Dh,Dl); //C251无法实现长整型数格式化字符串
ADDR=InputAdr(90,30,S); //输入要写入存储器的首地址
LCD_Str12(10,55,(char *)"Length=153600",10,0);
Length=153600; //一幅320*240图片数据长度
S[0]=Length/100000+'0';
S[1]=(Length%100000)/10000+'0';
S[2]=(Length%10000)/1000+'0';
S[3]=(Length%1000)/100+'0';
S[4]=(Length%100)/10+'0';
S[5]=Length%10+'0';
S[6]=0;
//sprintf(S,"%02d%06d",Dh,Dl);
Length=InputI(66,55,S); //输入要写入存储器的首地址
LCD_Str12(10,80,(char *)"FlashSector Start...",11,0);
sprintf(S,"FlashSector=%03d",Cnt);
LCD_Str12(10,105,S,11,0);
while(wait)
{ k=0;k=RDKEY();
if(k==K70)wait=0;
if(RX2_TimeOut>0) //如果已经有接收到字节
{ if(--RX2_TimeOut == 0) //超时计数减1等于0了:接收到一包数据了
{ if(RX2_Cnt>0)W25Q40_Write(ADDR,RX2_Buf,RX2_Cnt);//将数据写入制定地址的扇区中
Cnt++; sprintf(S,"%03d",Cnt); //接收计数++
LCD_Str12(106,105,S,15,0); //显示已经刷入的扇区(256字节)数
ADDR=ADDR+RX2_Cnt; //目标地址递增
RX2_Cnt=0; //计数清零
}
}
if(Cnt>=(Length/256))wait=0; //如果接收包数到达预定数,结束返回
}
LCD_Str12(10,130,"Flash End.",15,0);
GETCH(); //按任意键继续...
delay_ms(500); //延时
}
//读一页数据
void Read_W25Q(void)
{ unsigned int i,Dh,Dl;
unsigned char loop=1;
LCD_CLSA(0,25,160,150,0);
LCD_Str12(10,30,(char *)"Address=0x00000 (<=0x7FF00)",10,0);
Dh=ADDR / 65536; Dl=ADDR % 65536;
sprintf(S,"%1X%04X",Dh,Dl);
ADDR=InputAdr(90,30,S); //输入要读出存储器的首地址
ADDR &= 0x7FF00; //转页(256字节)地址
LCD_CLS(0);
while(loop)
{ Dh=ADDR / 65536; Dl=ADDR % 65536;
sprintf(S,"ADDR=0x%01X%04X",Dh,Dl);
LCD_Str12(0,0,S,10,0);
W25Q40_Read(ADDR,RX2_Buf,256);
for(i=0;i<256;i++)
{ sprintf(S,"%02X ",(unsigned int)RX2_Buf[i]);
LCD_Str12((i%16)*20,16+(i/16)*14,S,15,0);
}
k=0;k=GETCH();
switch(k) //长按或短按都可以...
{ case K40: case K41: ADDR=ADDR>0xFF?ADDR-256:0x7FF00; break;
case K50: case K51: ADDR=ADDR<0x7FF00?ADDR+256:0; break;
case K70: case K71: loop=0; break;
}
delay_ms(10); //延时
}
}
//删除扇区4096字节数据
void DelSector(void)
{ unsigned int Dh,Dl;
unsigned char set=1,OK=0;
LCD_CLSA(0,25,160,150,0);
LCD_Str12(10,30,(char *)"Address=0x00000 (<=0x7F000)",10,0);
Dh=ADDR / 65536; Dl=ADDR % 65536;
sprintf(S,"%1X%04X",Dh,Dl);
ADDR=InputAdr(90,30,S); //输入要读出存储器的首地址
ADDR &= 0x7F000; //转扇区(4096字节)地址
LCD_Str12(10,60,(char *)"Del Sector ??!",12,0);
while(set)
{ if(OK){ LCD_Str12(10,90,(char *)"NO!",15,0);LCD_Str12(50,90,(char *)"YES",14,4); }
else { LCD_Str12(10,90,(char *)"NO!",14,4);LCD_Str12(50,90,(char *)"YES",15,0); }
k=0;k=GETCH();
switch(k)
{ case K60: OK=OK<1?1:0; break;
case K70: set=0; break;
}
}
if(OK)
{ W25Q40_SectorErase(ADDR);
LCD_Str12(10,120,(char *)"Del Sector OK!",14,0);
delay_ms(1000); //延时
}
}
//删除块区64K字节数据
void DelBlock(void)
{ unsigned int Dh,Dl;
unsigned char set=1,OK=0;
LCD_CLSA(0,25,160,150,0);
LCD_Str12(10,30,(char *)"Address=0x00000 (<=0x70000)",10,0);
Dh=ADDR / 65536; Dl=ADDR % 65536;
sprintf(S,"%1X%04X",Dh,Dl);
ADDR=InputAdr(90,30,S); //输入要读出存储器的首地址
ADDR &= 0x70000; //转扇区(256字节)地址
LCD_Str12(10,60,(char *)"Del Block ??!",12,0);
while(set)
{ if(OK){ LCD_Str12(10,90,(char *)"NO!",15,0);LCD_Str12(50,90,(char *)"YES",14,4); }
else { LCD_Str12(10,90,(char *)"NO!",14,4);LCD_Str12(50,90,(char *)"YES",15,0); }
k=0;k=GETCH();
switch(k)
{ case K60: OK=OK<1?1:0; break;
case K70: set=0; break;
}
}
if(OK)
{ W25Q40_BlockErase(ADDR);
LCD_Str12(10,120,(char *)"Del Sector OK!",14,0);
delay_ms(1000); //延时
}
}
//显示全屏彩色图片
void DispBMP(unsigned long Addr)
{ unsigned int i,j,Col;
unsigned char h,l;
LCD_SetWindow(0,0,319,239); //设置显示窗口
for(i=0;i<600;i++)
{ W25Q40_Read(Addr,RX2_Buf,256);
for(j=0;j<128;j++)
{ h=RX2_Buf[2*j];l=RX2_Buf[2*j+1];
Col=256*h+l; //图像数据:高位在前.
LCD_WR_DAT_16Bit(Col);
}
Addr=Addr+256;
}
}
//显示BMP图片...
void Disp_PIC(void)
{
DispBMP(0x00000); //指定图片0数据的首地址
GETCH();
DispBMP(0x25800); //指定图片1数据的首地址
GETCH();
DispBMP(0x4B000); //指定图片2数据的首地址
GETCH();
delay_ms(500); //延时(防止菜单项连续被触发)
}
//=== Main.C END =================================================================================
|
|