久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 5105|回復(fù): 7
收起左側(cè)

帶字庫(kù)(GT20L16S1Y)LCD12864取字錯(cuò)誤偏移問題的思考

  [復(fù)制鏈接]
ID:686782 發(fā)表于 2020-7-8 23:04 | 顯示全部樓層 |閱讀模式
      最近買了一個(gè)LCD12864的屏幕,驅(qū)動(dòng)采用的是UC1701,SPI接口,字庫(kù)是高通的GT20L16S1Y。這里吐槽一下我拿到的官方字庫(kù)手冊(cè),居然沒有指明各種樣式字體的起始地址。不過在廠家給的例程里倒是能估計(jì)出來。在使用字庫(kù)例程修改加上我自己的SPI驅(qū)動(dòng)以后,便可以簡(jiǎn)單的顯示漢字了。一開始以為就這樣就好了,然后我打算將之前寫的一個(gè)電子鐘模塊移植過來時(shí),卻發(fā)現(xiàn)年,月,日這樣的字符都無法正常顯示:年是亂碼,月的字符偏移到了字庫(kù)里面“(六)”’該字符的位置,日的字符則是直接顯示“查”字。我一開始覺得是驅(qū)動(dòng)有問題,但是仔細(xì)想想又說不通,畢竟ascii字符也是可以讀取出來的。使用邏輯分析儀查看除了返回字模錯(cuò)亂,其他也是一切正常。如果驅(qū)動(dòng)有問題,也沒可能那么準(zhǔn)確的返回另一個(gè)字的字模。然后我就考慮是不是其他地方在copy的時(shí)候出現(xiàn)了錯(cuò)誤,類型不對(duì)溢出等。因?yàn)橹俺赃^這個(gè)虧,移植了一個(gè)stm32的程序到51上,結(jié)果MDK開發(fā)包與c51開發(fā)包的unsigned int類型有差異,導(dǎo)致了程序無緣無故的錯(cuò)誤。

      萬萬沒想到這次又吃了這個(gè)虧。
      因?yàn)閷ぶ匪惴ㄊ枪俜嚼烫峁┑模乙矝]有多考慮,debug的時(shí)候直接排除了這部分。并且在網(wǎng)上查找對(duì)比發(fā)現(xiàn)這套GB2312的計(jì)算方法確實(shí)是可行的。我把精力一直放在字庫(kù)偏移的問題上,進(jìn)行測(cè)試發(fā)現(xiàn),GB2312庫(kù)使用我的程序,大約在“繭”這個(gè)字左右開始,之后的所有字,要么是亂碼的無法顯示,要么是直接偏移到了前面的區(qū)位段去。雖然出錯(cuò),但是讀出的又是完整的字。很明顯發(fā)生了類似的溢出行為,但我百思不得其解,我代碼段里變量都已經(jīng)修改為unsigned long了,怎么還能溢出呢?該段代碼如下:

/***************************************************
16 點(diǎn)GB2312 標(biāo)準(zhǔn)點(diǎn)陣字庫(kù)
參數(shù)說明:
GBCode表示漢字內(nèi)碼。
MSB 表示漢字內(nèi)碼GBCode 的高8bits。
LSB 表示漢字內(nèi)碼GBCode 的低8bits。
Address 表示漢字或ASCII字符點(diǎn)陣在芯片中的字節(jié)地址。
BaseAdd:說明點(diǎn)陣數(shù)據(jù)在字庫(kù)芯片中的起始地址。
r_dat_bat 是讀點(diǎn)陣數(shù)據(jù)函數(shù)。
DZ_Data是保存讀出的點(diǎn)陣數(shù)據(jù)的數(shù)組。

*****************************************************/
void gt_16_GetData (u8 MSB,u8 LSB)
{
u32 BaseAdd=0,Address;
if(MSB == 0xA9 && LSB >=0xA1)
   Address = (282 + (LSB - 0xA1))*32+BaseAdd;
else if(MSB >=0xA1 && MSB <= 0xA3 && LSB >=0xA1)
       Address =( (MSB - 0xA1) * 94 + (LSB - 0xA1))*32+ BaseAdd;
else if(MSB >=0xB0 && MSB <= 0xF7 && LSB >=0xA1)
        Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;
r_dat_bat(Address,32,DZ_Data);
}


      在某一次搜索中,發(fā)現(xiàn)了中景園的字庫(kù)例程,我簡(jiǎn)單的對(duì)比了一下,基本上是相同的,但是在燒寫程序以后,中景園給的例程完全正常,除了臭名昭著的0xfd bug(具體可以在論壇或者網(wǎng)絡(luò)上搜索),顯示完全沒問題。看了一眼程序注釋,恍然大悟。代碼如下(篇幅問題只放一部分作對(duì)比,具體可站內(nèi)搜索):if(((text>=0xb0) &&(text<=0xf7))&&(text[i+1]>=0xa1))
                {                                                
                        /*國(guó)標(biāo)簡(jiǎn)體(GB2312)漢字在晶聯(lián)訊字庫(kù)IC中的地址由以下公式來計(jì)算:*/
                        /*Address = ((MSB - 0xB0) * 94 + (LSB - 0xA1)+ 846)*32+ BaseAdd;BaseAdd=0*/
                        /*由于擔(dān)心8位單片機(jī)有乘法溢出問題,所以分三部取地址*/
                        fontaddr = (text- 0xb0)*94;
                        fontaddr += (text[i+1]-0xa1)+846;
                        fontaddr = (ulong)(fontaddr*32);
                        
                        addrHigh = (fontaddr&0xff0000)>>16;  /*地址的高8位,共24位*/
                        addrMid = (fontaddr&0xff00)>>8;      /*地址的中8位,共24位*/
                        addrLow = fontaddr&0xff;             /*地址的低8位,共24位*/
                        get_n_bytes_data_from_ROM(addrHigh,addrMid,addrLow,fontbuf,32 );/*取32個(gè)字節(jié)的數(shù)據(jù),存到"fontbuf[32]"*/
                        display_graphic_16x16(y,x,fontbuf);/*顯示漢字到LCD上,y為頁(yè)地址,x為列地址,fontbuf[]為數(shù)據(jù)*/
                        i+=2;
                        x+=16;
                }
      這里提了一個(gè)關(guān)鍵詞 乘法溢出。之前在C語(yǔ)言,C++里面,相信大家都學(xué)習(xí)過不少相關(guān)的知識(shí)。例如整型提升,強(qiáng)制類型轉(zhuǎn)換等。uchar溢出的問題在剛寫程序的時(shí)候也經(jīng)常會(huì)遇到,常常是定時(shí)器相關(guān)。這里引用一名為的“keil大常量計(jì)算問題”的博客來做解釋,我自己講的可能不太準(zhǔn)確。
該博客提到:
      keil C51是與ANSI C兼容的編譯器,ANSI C規(guī)范規(guī)定十進(jìn)制整數(shù)常量的默認(rèn)數(shù)據(jù)類型是int、long int和unsigned long int的其中一種,對(duì)給定的常量是其中的哪一種要看這個(gè)常量的實(shí)際大小,如果常數(shù)在-32768~32767之間則按int類型處理,如果按int類型處理會(huì)溢出就考慮long int或更大的數(shù)據(jù)類型unsigned long int。總之,編譯器總是按盡可能的原則指定常量的類型。但這一原則并不總能奏效,當(dāng)兩個(gè)常量做運(yùn)算時(shí)就可能導(dǎo)致溢出。如:
    #define SYSCLK  22118400// SYSCLK in Hz (22.1184 MHz external crystal oscillator)
    #define SLIDER_REST_TIME  100// in ms,slider rest time
    #define REST_DELAY    SYSCLK * SLIDER_REST_TIME / (65536 * 1000)
    unsigned char i;
    i = REST_DELAY;
       在keil c51中運(yùn)行i為0xE1,即225,并不是期望的結(jié)果22118400 * 100 / (65536 * 1000) = 33.75,取整為33。原因分析如下:
宏替換后為:i = 22118400 * 100 / (65536 * 1000);,編譯器首先為22118400定義類型,因?yàn)?2118400不在int的表示范圍內(nèi),而在long int的范圍-2147483648~2147483647內(nèi),所以22118400按long int類型處理,在做乘積運(yùn)算時(shí)100被自動(dòng)按long int處理,22118400 * 100將按兩帶符號(hào)長(zhǎng)整型常量進(jìn)行運(yùn)算,運(yùn)算結(jié)果仍為帶符號(hào)長(zhǎng)整型,結(jié)果寫成十六進(jìn)制是0x83D60000,其十進(jìn)制是-2083127296,顯然出現(xiàn)了溢出錯(cuò)誤。keil編譯器并沒有給出任何錯(cuò)誤或警告提示信息(VC++6.0還給出警告warning C4307: * : integral constant overflow),繼續(xù)進(jìn)行下一個(gè)運(yùn)算65536 * 1000,結(jié)果為帶符號(hào)長(zhǎng)整型,十六進(jìn)制為0x3E80000,十進(jìn)制為65536000,最后按兩長(zhǎng)整型除法計(jì)算-2083127296 / 65536000,結(jié)果為0xFFFFFFE1,由于i為字符類型,取0xFFFFFFE1的最低有效字節(jié)為0xE1賦值給i,i的最終值為0xE1。
      解決這種溢出錯(cuò)誤的方法用C語(yǔ)言的一個(gè)術(shù)語(yǔ)就是“提升”(promotion),拿上例來說就是將22118400指定為無符號(hào)長(zhǎng)整型,即:
         # define SYSCLK 22118400UL
       注:雖然只要將22118400、100、65536和1000四個(gè)常數(shù)中的一個(gè)指定為無符號(hào)長(zhǎng)整型即可得到正確的結(jié)果,但考慮到可讀性及規(guī)范性,應(yīng)選擇大整數(shù)指定其類型。-----------------------------
       通過以上說明我們可以看見,這一切起因是常量造成的整型提升。以我的字庫(kù)程序?yàn)槔褪?4,被默認(rèn)成為了int,而繭對(duì)應(yīng)的機(jī)內(nèi)碼為BCEB,MSB為BC,LSB為EB,經(jīng)過計(jì)算可以得到,該式子為(1128+74+846)*32,合并一下,即為2048*32,這個(gè)數(shù)字大家一定很熟悉吧,2的十五次,對(duì)應(yīng)int類型,恰好發(fā)生溢出。因此,繭字以后發(fā)生溢出便得到了解釋。本身LSB和MSB屬于無符號(hào)char,但常數(shù)94等默認(rèn)為有符號(hào)int,在一起計(jì)算的過程中uchar被提升,整體結(jié)果以int的形式呈現(xiàn),而這時(shí)中間結(jié)果發(fā)生了溢出,無法在正常通過賦值提升為ulong類型提供正確地址。因此,字庫(kù)顯示范圍永遠(yuǎn)被現(xiàn)在那個(gè)大小。再看中景園的程序,實(shí)際上是提前進(jìn)行ulong轉(zhuǎn)化的步驟,提前存儲(chǔ)中間結(jié)果,防止其在進(jìn)行乘法時(shí)溢出。同時(shí)也可以想到常量后綴的方法,將94等修改為94L,或者使用(unsigned long)進(jìn)行強(qiáng)制轉(zhuǎn)化,則程序也可以正常運(yùn)行。

正常運(yùn)行

正常運(yùn)行

存在乘法溢出風(fēng)險(xiǎn)

存在乘法溢出風(fēng)險(xiǎn)


      因此,大家以后在做這種容易涉及溢出的問題的時(shí)候,一定要多留個(gè)心眼,例如及時(shí)將常量加上后綴,以防止意料之外的溢出問題產(chǎn)生。我這個(gè)源程序其實(shí)是沒問題的,MDK環(huán)境下能正常運(yùn)行,因?yàn)閕nt的位數(shù)問題,導(dǎo)致了stm32使用該程序時(shí),字庫(kù)無論怎么取也不會(huì)出現(xiàn)這個(gè)溢出。因此大家在移植程序時(shí)也要在這方面多加考慮。

      總體看其實(shí)是一個(gè)相當(dāng)愚蠢的問題,卻困擾了我好多天。。一直沒想到乘法溢出的問題,C語(yǔ)言功底還是不夠扎實(shí)。總之吃一塹長(zhǎng)一智,希望大家能吸取我的經(jīng)驗(yàn)教訓(xùn)吧,也希望能幫到使用了該例程而感到困惑的朋友。

評(píng)分

參與人數(shù) 2黑幣 +110 收起 理由
gjwhs + 10 很給力!
admin + 100 共享資料的黑幣獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

ID:1044755 發(fā)表于 2024-10-31 12:52 | 顯示全部樓層
感謝,遇到同樣的問題
回復(fù)

使用道具 舉報(bào)

ID:1068432 發(fā)表于 2023-3-29 13:52 | 顯示全部樓層
謝謝大佬點(diǎn)醒夢(mèng)中人(我=====小白)
回復(fù)

使用道具 舉報(bào)

ID:463392 發(fā)表于 2023-3-24 15:11 | 顯示全部樓層
1123213124 發(fā)表于 2023-3-23 17:07
請(qǐng)問怎么獲取該芯片字庫(kù)的lcd12864屏幕

http://www.zg4o1577.cn/bbs/dpj-216347-1.html
回復(fù)

使用道具 舉報(bào)

ID:994947 發(fā)表于 2023-3-23 17:07 | 顯示全部樓層
請(qǐng)問怎么獲取該芯片字庫(kù)的lcd12864屏幕
回復(fù)

使用道具 舉報(bào)

ID:996773 發(fā)表于 2023-1-3 14:51 | 顯示全部樓層
本人才疏學(xué)淺,只是直接利用字符表的地址串行輸入12864顯示漢字很正常,沒有樓主的不能使用的煩惱
回復(fù)

使用道具 舉報(bào)

ID:373 發(fā)表于 2022-12-27 16:35 | 顯示全部樓層
學(xué)習(xí)一下,正使用這個(gè)芯片
回復(fù)

使用道具 舉報(bào)

ID:686782 發(fā)表于 2020-7-8 23:27 | 顯示全部樓層
網(wǎng)上常說的keil漢字編碼方式需要修改成GB2312我個(gè)人沒什么感覺,我使用的是ANSI C,也是可以正常編碼的,使用UTF-8還可以直接看到漢字的機(jī)內(nèi)碼。總而言之,漢字在字符串里顯示正確一般是沒有什么問題的。
至于0xfd bug,有些版本的補(bǔ)丁貌似在keil 4,keil 5無法奏效了,顯示查找不到,我這里順便也上傳一下我驗(yàn)證了可以正常使用的版本,我是keil5。

51黑論壇_KeilFDfix_b7(冠銘師兄版).rar

96.79 KB, 下載次數(shù): 32, 下載積分: 黑幣 -5

KeilFDfix_b7(冠銘師兄版)

評(píng)分

參與人數(shù) 1黑幣 +20 收起 理由
admin + 20 回帖助人的獎(jiǎng)勵(lì)!

查看全部評(píng)分

回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 美女久久久久久久 | 日本一区二区三区在线观看 | 免费精品国产 | 国产一级电影网 | 在线观看国产 | 国产激情视频网站 | 亚洲精品在线观看视频 | 亚洲精品一区二区 | 一区二区视频在线 | 国产精品美女 | 伊人影院在线观看 | 国产精品国产三级国产aⅴ原创 | 久久久久国产精品一区二区 | 午夜专区| 精品亚洲一区二区 | 天堂久久网| 中文字幕亚洲区 | 一区二区中文字幕 | 欧美亚洲另类在线 | 国产美女在线观看 | 天天天操操操 | 欧美1区 | 久久精品欧美一区二区三区不卡 | 毛片免费看的 | 亚洲成人自拍 | 91视频a | 欧美又大粗又爽又黄大片视频 | 日日骚视频 | 午夜av电影 | 亚洲精品免费在线 | 国产精品99久久久久久人 | 香蕉久久av | ww亚洲ww亚在线观看 | 亚洲欧美一区二区三区情侣bbw | 日韩在线一区二区三区 | h视频在线免费观看 | 欧美日韩在线视频一区 | 国产亚洲网站 | 欧美一级欧美三级在线观看 | 九色视频网站 | 日本久久综合 |