基于探索者串口更新字库笔记
生活随笔
收集整理的這篇文章主要介紹了
基于探索者串口更新字库笔记
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
基于探索者串口更新字庫筆記
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通道4while (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;elseGBK_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.BINftinfo.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最后的一幀數據寫入FLASHelseW25QXX_Write(USART1_Rece_Buf0,offx+flashaddr,USART1_DMA_Len-DMA_GetCurrDataCounter(DMA2_Stream5));//將DMA最后的一幀數據寫入FLASHprintf("This Font updated successfull!\r\n");uart_init(BAUD_RATE); //重新初始化串口及DMAGBK_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.FONLCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK12.FON ");updata_fontx(x+20*size/2,y,size,1); //更新GBK12.FONLCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK16.FON ");updata_fontx(x+20*size/2,y,size,2); //更新GBK16.FONLCD_ShowString(x,y,240,320,size,(u8*)"Updating GBK24.FON ");updata_fontx(x+20*size/2,y,size,3); //更新GBK16.FONLCD_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;//下一個漢字偏移 } } }總結
以上是生活随笔為你收集整理的基于探索者串口更新字库笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MRP问答
- 下一篇: 博客园文章索引生成器