基于探索者串口更新字库笔记

基于探索者串口更新字库笔记

W25Q128

通信方式是SPI,读数据可以从任何地方读,写数据和擦出数据需要按照页或者扇区或者簇为单位进行。

写数据:一次最多写一页,如果超出一页数据长度,则分几次完成。本芯片一个扇区为4096个字节,那么需要写16页,要进行至少16次按页写数据。

擦数据:擦数据的最小单位是一个扇区,也可以直接擦出整个芯片。

容量:16Mbytes  一页为256个字节   一个扇区为4096个字节

额,还没有自己独立写驱动代码的能力,直接使用的正点原子例程。

DMA

DMA全称DirectMemoryAccess,即直接存储器访问。

DMA传输将数据从一个地址空间复制到另一个地址空间。当CPU初始化这个传输动作,传输动作本身是由DMA控制器来实现和完成的。

DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和I0设备开辟一条直接传输数据的通道,使得CPU的效率大大提高。

作用: 为CPU减负

在这里插入图片描述
在这里插入图片描述

串口配置

重要代码

	DMA_InitTypeDef DMA_InitStructure;
	//DMA配置
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2 时钟使能
	DMA_DeInit(DMA2_Stream5);    //恢复默认值 串口1接收是DMA2数据流2通道4
	while (DMA_GetCmdStatus(DMA2_Stream5) != DISABLE){}//等待 DMA 可配置
	/* 配置 DMA Stream */
	DMA_InitStructure.DMA_Channel = DMA_Channel_4; //通道选择
	DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&USART1->DR;//DMA 外设地址
	DMA_InitStructure.DMA_Memory0BaseAddr = (u32)USART1_Rece_Buf0;//DMA 存储器 0 地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到存储器模式
	DMA_InitStructure.DMA_BufferSize = USART1_DMA_Len;//数据传输量
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设非增量模式
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//存储器增量模式
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设数据长度:8 位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//存储器数据长度:8 位	
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//注意:这里设置为循环模式,不然不能启动第二次传输
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFO 模式禁止
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;//FIFO 阈值
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发单次传输
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发单次传输
	DMA_DoubleBufferModeConfig(DMA2_Stream5, (uint32_t)USART1_Rece_Buf1, DMA_Memory_0);  //USART1_Rece_Buf0 先缓冲
    DMA_DoubleBufferModeCmd(DMA2_Stream5, ENABLE);	
		
	DMA_Init(DMA2_Stream5, &DMA_InitStructure);//初始化 DMA Stream	
	DMA_Cmd(DMA2_Stream5, ENABLE); //开启 DMA 传输
	
	DMA_ITConfig(DMA2_Stream5,DMA_IT_TC,ENABLE);	//使能DMA传输完成中断
	//开启一次 DMA 传输
	//DMA_Streamx:DMA 数据流,DMA1_Stream0~7/DMA2_Stream0~7
	//ndtr:数据传输量
	void MYDMA_Enable(DMA_Stream_TypeDef *DMA_Streamx,u16 ndtr)
	{
		DMA_Cmd(DMA_Streamx, DISABLE); //关闭 DMA 传输
		while (DMA_GetCmdStatus(DMA_Streamx) != DISABLE){} //确保 DMA 可以被设置
		DMA_SetCurrDataCounter(DMA_Streamx,ndtr); //数据传输量
		DMA_Cmd(DMA_Streamx, ENABLE); //开启 DMA 传输
	}
	
	
	void USART1_IRQHandler(void)                	//串口1中断服务程序
	{
	
		if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
		{
	    USART_ReceiveData(USART1);//(USART1->DR);	//读取接收到的数据 		 
    	  } 
	
	}  
	
	void DMA2_Stream5_IRQHandler(void)                	
	{
	
	 if(DMA_GetFlagStatus(DMA2_Stream5,DMA_FLAG_TCIF5)==SET) 
		{
	    DMA_ClearFlag(DMA2_Stream5,DMA_FLAG_TCIF5);	  
			
			//**********************数据帧处理******************//
			if(1==DMA_GetCurrentMemoryTarget(DMA2_Stream5))
				GBK_BUF_Flag=0;
			else
				GBK_BUF_Flag=1;
			//**************************************************//
	
	  		 
	  } 
	} 
	
	
	void send(u8 ch)
	{
	  while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
		USART1->DR = (u8) ch;   
	}
	 
	

DMA配置过程

在这里插入图片描述

更新过程

使用串口将GBK文件通过DMA跳过CPU直接写入W25Q128
重要代码:

“fontupd.h”

	//字体信息保存地址,占33个字节,第1个字节用于标记字库是否存在.后续每8个字节一组,分别保存起始地址和文件大小														   
	extern u32 FONTINFOADDR;	
	//字库信息结构体定义
	//用来保存字库基本信息,地址,大小等
	//增加新的字库需要在结构体中添加所需的字体地址及大小
	__packed typedef struct 
	{
		u8 fontok;				//字库存在标志,0XAA,字库正常;其他,字库不存在
		u32 ugbkaddr; 			//unigbk的地址
		u32 ugbksize;			//unigbk的大小	 
		u32 f12addr;			//gbk12地址	
		u32 gbk12size;			//gbk12的大小	 
		u32 f16addr;			//gbk16地址
		u32 gbk16size;			//gbk16的大小		 
		u32 f24addr;			//gbk24地址
		u32 gkb24size;			//gbk24的大小 		 
		u32 f32addr;			//gbk24地址
		u32 gkb32size;			//gbk24的大小 
	}_font_info; 


	extern _font_info ftinfo;	//字库信息结构体
	
	u32 fupd_prog(u16 x,u16 y,u8 size,u32 fsize,u32 pos);	//显示更新进度
	u8 updata_fontx(u16 x,u16 y,u8 size,u8 fx);	//更新指定字库
	u8 update_font(u16 x,u16 y,u8 size);			//更新全部字库
	u8 font_init(void);										//初始化字库

“fontupd.c”

	//字库区域占用的总扇区数大小(3个字库+unigbk表+字库信息=3238700字节,约占791个W25QXX扇区)
	#define FONTSECSIZE	 	1539  //1539个扇区6303000字节  必须能够整除4096 因为一个扇区4096
	//字库存放起始地址 
	#define FONTINFOADDR 	1024*1024*0 		//字库存放首地址
	//定义各个字库的大小
	#define UNIGBK         171*1024        //171KB
	#define GBK12_FONSIZE  562*1024        //562KB
	#define GBK16_FONSIZE  749*1024			   //749KB
	#define GBK24_FONSIZE  1684*1024       //1684KB
	#define GBK32_FONSIZE  2993*1024       //1684KB
	//用来保存字库基本信息,地址,大小等
	_font_info ftinfo;
	//更新某一个
	//x,y:坐标
	//size:字体大小
	//fx:更新的内容 0,ungbk;1,gbk12;2,gbk16;3,gbk24;
	//返回值:0,成功;其他,失败.
	u8 updata_fontx(u16 x,u16 y,u8 size,u8 fx)
	{
		u32 flashaddr=0;								    
	 	u8 res;	
		u32 offx=0;    
	  u32 fsize=0;
			switch(fx)
			{
			   //添加新字库需要修改的地方
				case 0:												//更新UNIGBK.BIN
					ftinfo.ugbkaddr=FONTINFOADDR+sizeof(ftinfo);	//信息头之后,紧跟UNIGBK转换码表
					fsize=ftinfo.ugbksize=UNIGBK;					//UNIGBK大小
					flashaddr=ftinfo.ugbkaddr;
				  printf("Please send UNIGBK.bin\r\n");
					break;
				case 1:
					ftinfo.f12addr=ftinfo.ugbkaddr+ftinfo.ugbksize;	//UNIGBK之后,紧跟GBK12字库
					fsize=ftinfo.gbk12size=GBK12_FONSIZE;					//GBK12字库大小
					flashaddr=ftinfo.f12addr;						//GBK12的起始地址
				  printf("Please send GBK12.FON\r\n");
					break;
				case 2:
					ftinfo.f16addr=ftinfo.f12addr+ftinfo.gbk12size;	//GBK12之后,紧跟GBK16字库
					fsize=ftinfo.gbk16size=GBK16_FONSIZE;					//GBK16字库大小
					flashaddr=ftinfo.f16addr;						//GBK16的起始地址
				  printf("Please send GBK16.FON\r\n");
					break;
				case 3:
					ftinfo.f24addr=ftinfo.f16addr+ftinfo.gbk16size;	//GBK16之后,紧跟GBK24字库
					fsize=ftinfo.gkb24size=GBK24_FONSIZE;					//GBK24字库大小
					flashaddr=ftinfo.f24addr;						//GBK24的起始地址
				  printf("Please send GBK24.FON\r\n");
					break;
				case 4:
					ftinfo.f32addr=ftinfo.f24addr+ftinfo.gkb24size;	//GBK16之后,紧跟GBK24字库
					fsize=ftinfo.gkb32size=GBK32_FONSIZE;					//GBK24字库大小
					flashaddr=ftinfo.f32addr;						//GBK24的起始地址
				  printf("Please send GBK32.FON\r\n");
					break;
			} 
			
			fupd_prog(x,y,size,fsize,offx);	 			//进度显示
			while(1)//死循环执行
			{
		 		if(GBK_OVER_Flag)
	 				GBK_OVER_Flag++;
				if(GBK_BUF_Flag!=2)
				{
					GBK_OVER_Flag=1;
					if(GBK_BUF_Flag==0)
						W25QXX_Write(USART1_Rece_Buf0,offx+flashaddr,USART1_DMA_Len);		//开始写入USART1_DMA_Len个数据  
					else if(GBK_BUF_Flag==1)
						W25QXX_Write(USART1_Rece_Buf1,offx+flashaddr,USART1_DMA_Len);		//开始写入USART1_DMA_Len个数据  
					offx+=USART1_DMA_Len;
					GBK_BUF_Flag=2;
					fupd_prog(x,y,size,fsize,offx);	 			//进度显示
				}
				delay_us(100);
				if(GBK_OVER_Flag>(WATE_TIME+10)*10)   //超过正常时间10ms则说明此字库发送完毕
					break;
		 	} 
			if(DMA_GetCurrentMemoryTarget(DMA2_Stream5)==1)
			   W25QXX_Write(USART1_Rece_Buf1,offx+flashaddr,USART1_DMA_Len-DMA_GetCurrDataCounter(DMA2_Stream5));//将DMA最后的一帧数据写入FLASH
			else
				 W25QXX_Write(USART1_Rece_Buf0,offx+flashaddr,USART1_DMA_Len-DMA_GetCurrDataCounter(DMA2_Stream5));//将DMA最后的一帧数据写入FLASH
			
			printf("This Font updated successfull!\r\n");
			uart_init(BAUD_RATE);		//重新初始化串口及DMA
			GBK_OVER_Flag=0;
	
		return res;
	} 
	
	//更新字体文件,UNIGBK,GBK12,GBK16,GBK24一起更新
	//x,y:提示信息的显示地址
	//size:字体大小
	//提示信息字体大小										  
	//返回值:0,更新成功;
	//		 其他,错误代码.	  
	u8 update_font(u16 x,u16 y,u8 size)
	{	
		 u16 i,j;
		
		 LCD_ShowString(x,y,240,320,size,(u8*)"Erasing sectors... ");//提示正在擦除扇区	
			for(i=0;i<FONTSECSIZE;i++)	//先擦除字库区域,提高写入速度
			{
	      fupd_prog(x+20*size/2,y,size,FONTSECSIZE,i);//进度显示
				W25QXX_Read((u8*)USART1_Rece_Buf1,((FONTINFOADDR/4096)+i)*4096,4096);//读出整个扇区的内容(借用一下DMA缓冲区)
				for(j=0;j<4096;j++)//校验数据
				{
					if(USART1_Rece_Buf1[j]!=0XFF)break;//需要擦除  	  
				}
				if(j!=4096)W25QXX_Erase_Sector((FONTINFOADDR/4096)+i);	//需要擦除的扇区
			}
			delay_ms(100);
			
			LCD_ShowString(x,y,240,320,size,(u8*)"Updating UNIGBK.BIN  ");
			updata_fontx(x+20*size/2,y,size,0);	//更新GBK12.FON
			LCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK12.FON  ");
			updata_fontx(x+20*size/2,y,size,1);	//更新GBK12.FON
			LCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK16.FON  ");
			updata_fontx(x+20*size/2,y,size,2);	//更新GBK16.FON
			LCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK24.FON  ");
			updata_fontx(x+20*size/2,y,size,3);	//更新GBK16.FON
			LCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK32.FON  ");
			updata_fontx(x+20*size/2,y,size,4);	//更新GBK16.FON		
			
			//全部更新好了
			ftinfo.fontok=0XAA;
			W25QXX_Write((u8*)&ftinfo,FONTINFOADDR,sizeof(ftinfo));	//保存字库信息
			printf("All Font file updated successfull!!!\r\n");
			LCD_Clear(WHITE);
			
			return 0;
	}

使用字库相关代码

text.h

	void Get_HzMat(unsigned char *code,unsigned char *mat,u8 size);			//得到汉字的点阵码
	void Show_Font(u16 x,u16 y,u8 *font,u8 size,u8 mode);					//在指定位置显示一个汉字
	void Show_Str(u16 x,u16 y,u16 width,u16 height,u8*str,u8 size,u8 mode);	//在指定位置显示一个字符串 
	void Show_Str_Mid(u16 x,u16 y,u8*str,u8 size,u8 len);

text.c

	//code 字符指针开始
	//从字库中查找出字模
	//code 字符串的开始地址,GBK码
	//mat  数据存放地址 (size/8+((size%8)?1:0))*(size) bytes大小	
	//size:字体大小
	void Get_HzMat(unsigned char *code,unsigned char *mat,u8 size)
	{		    
		unsigned char qh,ql;
		unsigned char i;					  
		unsigned long foffset; 
		u8 csize=(size/8+((size%8)?1:0))*(size);//得到字体一个字符对应点阵集所占的字节数	 
		qh=*code;
		ql=*(++code);
		if(qh<0x81||ql<0x40||ql==0xff||qh==0xff)//非 常用汉字
		{   		    
		    for(i=0;i<csize;i++)*mat++=0x00;//填充满格
		    return; //结束访问
		}          
		if(ql<0x7f)ql-=0x40;//注意!
		else ql-=0x41;
		qh-=0x81;   
		foffset=((unsigned long)190*qh+ql)*csize;	//得到字库中的字节偏移量  		  
		switch(size)
		{
			case 12:
				W25QXX_Read(mat,foffset+ftinfo.f12addr,csize);
				break;
			case 16:
				W25QXX_Read(mat,foffset+ftinfo.f16addr,csize);
				break;
			case 24:
				W25QXX_Read(mat,foffset+ftinfo.f24addr,csize);
				break;
			case 32:
				W25QXX_Read(mat,foffset+ftinfo.f32addr,csize);
				break;
				
		}     												    
	}  
	//在指定位置开始显示一个字符串	    
	//支持自动换行
	//(x,y):起始坐标
	//width,height:区域
	//str  :字符串
	//size :字体大小
	//mode:0,非叠加方式;1,叠加方式    	   		   
	void Show_Str(u16 x,u16 y,u16 width,u16 height,u8*str,u8 size,u8 mode)
	{					
		u16 x0=x;
		u16 y0=y;							  	  
	    u8 bHz=0;     //字符或者中文  	    				    				  	  
	    while(*str!=0)//数据未结束
	    { 
	        if(!bHz)
	        {
		        if(*str>0x80)bHz=1;//中文 
		        else              //字符
		        {      
	                if(x>(x0+width-size/2))//换行
					{				   
						y+=size;
						x=x0;	   
					}							    
			        if(y>(y0+height-size))break;//越界返回      
			        if(*str==13)//换行符号
			        {         
			            y+=size;
						x=x0;
			            str++; 
			        }  
			        else LCD_ShowChar(x,y,*str,size,mode);//有效部分写入 
					str++; 
			        x+=size/2; //字符,为全字的一半 
		        }
	        }else//中文 
	        {     
	            bHz=0;//有汉字库    
	            if(x>(x0+width-size))//换行
				{	    
					y+=size;
					x=x0;		  
				}
		        if(y>(y0+height-size))break;//越界返回  						     
		        Show_Font(x,y,str,size,mode); //显示这个汉字,空心显示 
		        str+=2; 
		        x+=size;//下一个汉字偏移	    
	        }						 
	    }   
	}  	
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值