娇小w搡bbbb搡bbb,《第一次の人妻》,中国成熟妇女毛茸茸,边啃奶头边躁狠狠躁视频免费观看

歷史上的今天

今天是:2025年05月31日(星期六)

2019年05月31日 | STM32HAL庫使用SPI驅動1.44寸TFTLCD

發布者:恬淡如云 來源: eefocus關鍵字:STM32  HAL庫  SPI驅動  TFTLCD 手機看文章 掃描二維碼
隨時隨地手機看文章

??關于STM32F4單片機,使用HAL庫自帶的SPI,驅動TFTLCD屏幕的資料網上好像不太多,正好最近我做了這項工作,把成果分享給大家。我的代碼實現了這些功能:任意坐標畫點,指定首尾坐標畫線,畫方框,指定區域顯示彩圖,顯示16* 16或者12* 12的漢字、ASCII碼,并附帶ASCII碼表與少量的漢字字庫。


硬件設計

??屏幕選擇:使用了一款低成本十六位彩屏,只要十塊錢。鏈接

在這里插入圖片描述

??廠家看到文章請聯系我打廣告費,哈哈。

??雖然用這個屏幕的可能不多,但我了解到,只要其控制芯片是ST7735S,那么程序就應該差不多。不同的地方在于,廠家的封裝與玻璃不太一樣,玻璃有個伽馬值不同,會導致顏色看上去不太一樣。


??屏幕的引腳信息

在這里插入圖片描述

??我的原理圖設計:使用了STM32F405RG芯片的SPI1,屏幕沒有MISO。


在這里插入圖片描述
在這里插入圖片描述

cubeMX中SPI的配置大致如下:

在這里插入圖片描述在這里插入圖片描述

??其實SPI的速度我選的是21MBITS/s,可能再快一點也行,沒有測試。

??其它引腳比較散,都是當做IO來用,CubeMX中的配置過程就不說了,匯總如下


名稱 引腳 功能

LCD_RST PC5 屏幕復位

LCD_CD PB0 0數據1指令

SPI_MOSI PB5 數據線

SPI_CLK PB3 時鐘線

LCD_CS PB1 片選,低電平有效

LCD_LED PB2 背光,高電平有效

發送數據與指令的基本函數

??在引腳初始化以后,我定義了幾個位帶操作,方便操作引腳


#define LCD_RST   PCout(5)

#define LCD_CD    PBout(0)

#define LCD_CS    PBout(1)

#define LCD_LED   PBout(2)


??不論是發送數據還是引腳,我都采用了HAL庫提供的現成的SPI發送函數:


??很多人在使用STM32的SPI時都用模擬SPI,說STM32的硬件SPI有問題,我暫時沒有發現硬件SPI的問題。不過模擬SPI很容易講清楚原理,按位發送數據,一般寫法是這樣的:


      for(i=0;i<8;i++)

      {

          if(dat&0x80)

      {

      SDA=1;

??如果你沒有使用HAL庫,可以把HAL_SPI_Transmit替換掉。

??發送數據與指令的區別就在于LCD_CD引腳的電平狀態,兩個函數如下:


/**

  * @brief 向LCD屏幕寫一個字節的命令

  * @param 命令內容,具體命令可以參照手冊

  * @retval None

  */

static void LCD_WriteCommand(uint8_t temp)

{

LCD_CD = 0;

LCD_CS = 0;

HAL_SPI_Transmit(&hspi1,&temp, 1, 0xffff);

LCD_CS = 1;

}

/**

  * @brief 向LCD屏幕寫一個字節的數據

  * @param 數據

  * @retval None

  */

static void LCD_WriteData(uint8_t temp)

{

LCD_CD = 1;

LCD_CS = 0;

HAL_SPI_Transmit(&hspi1,&temp, 1, 0xffff);

LCD_CS = 1;

}


??可以看出來,除了LCD_CD引腳用于切換命令,也需要操作LCD_CS來選中屏幕。個人認為操作過多操作引腳會影響效率,而發送數據的函數應用的十分頻繁,特別是對于我們選用的十六位屏幕,每個像素都需要十六位的數據,所以,我們經常用到的功能是發送個十六位的數據。代碼可以這么寫,調用兩次發送8位數據的函數:


static void LCD_WD_U16(u16 temp)

{

    LCD_WriteData(temp>>8);

    LCD_WriteData(temp);

}


??由于要操作兩次IO,所以我稍微做了一點優化:


/**

  * @brief 向LCD屏幕寫兩個字節的數據

  * @param 16位的數據

* @note  此函數可以直接調用LCD_WriteData兩次,但是IO的操作是多余的

  *        由于每個圖片的數據都是16位的,所以此函數很常用,因此稍作優化,減少操作IO

  * @retval None

  */

static void LCD_WD_U16(u16 temp)

{

u8 tempBuf[2];

tempBuf[0] = temp>>8;

tempBuf[1] = temp;

LCD_CD = 1;

LCD_CS = 0;

HAL_SPI_Transmit(&hspi1,tempBuf, 2, 0xffff);

LCD_CS = 1;

}


??同理寫了一個函數,用于發送數組。彩圖數組動輒都是上萬位的,并且是連續發送數據,所以也不需要操作多次IO。


/**

  * @brief 向LCD屏幕寫一個數組的長度

  * @param 數組地址與長度

* @note  此函數可以直接調用LCD_WriteData若干次,但是IO的操作是多余的

  *        由于每個圖片的數據都是16位的很長的數組,所以此函數很常用,因此稍作優化,減少操作IO,一個圖片的數組值操作一次IO

  * @retval None

  */

static void LCD_WD_buf(uint8_t *pData, uint16_t Size)

{

LCD_CD = 1;

LCD_CS = 0;

HAL_SPI_Transmit(&hspi1,pData, Size, 0xffff);

LCD_CS = 1;

}


初始化與定位

??初始化代碼太長,就不放了。其實初始化代碼是廠家提供的,只不過原來是51程序,我移植了下。

??屏幕的顯示需要坐標系,定位操作其實就是發個特定的命令,表示設置x/y軸,在發送特定的數據,表示具體位置。操作思路在《ST7735S手冊》中都有體現,例如設置列地址:

在這里插入圖片描述

??我們找到了設置列地址的命令,再把自己需要的坐標計算出來,假如全屏顯示:


/**

  * @brief 設置顯示區域為全屏

  * @param None

  * @retval None

  */

static void Full_Screen(void)

{

LCD_WriteCommand(0x2A);     //設置列地址

LCD_WriteData(0x00);

LCD_WriteData(0x02);

LCD_WriteData(0x00);

LCD_WriteData(0x81);


LCD_WriteCommand(0x2B);     //設置行地址

LCD_WriteData(0x00);

LCD_WriteData(0x03);

LCD_WriteData(0x00);

LCD_WriteData(0x82);


LCD_WriteCommand(0x2C);   //寫內存

}


??設置某個點的坐標:


/**

  * @brief 設置某個點的坐標

  * @param 點的橫縱坐標

* @note  坐標的起點為(2,3)

  * @retval None

  */

static void LCD_SetXY(u16 x,u16 y)

{

LCD_WriteCommand(0x2A);     //設置橫軸

LCD_WD_U16(x+2);

LCD_WriteCommand(0x2B);     //設置縱軸

LCD_WD_U16(y+3);

LCD_WriteCommand(0x2C);   //寫內存

}


??設置某個區域的坐標:


/**

  * @brief 設置某個顯示區域的坐標

  * @param 區域左上角的坐標與右下角的坐標

* @note  坐標的起點為(2,3)

  * @retval None

  */

static void LCD_SetArea(u16 x0, u16 y0,u16 x1, u16 y1)

{

LCD_WriteCommand(0x2A);     //設置橫軸

LCD_WD_U16(x0+2);

LCD_WD_U16(x1+2);

LCD_WriteCommand(0x2B);     //設置縱軸

LCD_WD_U16(y0+3);

LCD_WD_U16(y1+3);

LCD_WriteCommand(0x2C);   //寫內存

}


顏色的確定

??所謂十六位真彩色,意思就是每個像素的顏色由十六位決定。我們在初始化函數中設置的是這樣分配的:

在這里插入圖片描述

??紅色5位,綠色6位,藍色5位

??很容易想到白色的RGB值就是0xffff,黑色是0x0000。其它還有幾個顏色的定義如下:


#define RED    0xf800

#define GREEN  0x07e0

#define BLUE   0x001f

#define YELLOW 0xffe0

#define WHITE  0xffff

#define BLACK  0x0000

#define PURPLE 0xf81f


??一定要注意,高位在前。有很多取色工具可以幫我們算出某個顏色的RGB值。


畫點、線、框

??前邊已經寫了確定點坐標的方法,畫點就十分簡單了:


/**

  * @brief 畫一個點

  * @param 點的橫縱坐標,點的顏色

  * @retval None

  */

void LCD_DrawPoint(u16 x,u16 y,u16 color)

{

LCD_SetXY(x,y);

LCD_WD_U16(color);

}


??畫線函數理論上來講就是調用多次畫點的函數。如果是橫平豎直的線,那十分簡單了。如果是斜線呢?那就需要考慮斜率了。由于像素是離散的,所以線上的點,我們只處理所謂的整數部分,代碼比較復雜,主要是因為整型變量處理四舍五入的小數部分稍微有點吃力。


/**

  * @brief 畫一條線

  * @param 線的起點與終點的橫縱坐標,顏色

* @note  可以畫斜線

  * @retval None

  */

void LCD_DrawLine(u16 x0, u16 y0,u16 x1, u16 y1,u16 Color)   

{

int dx,             // x軸上的距離

    dy,             // y軸上的距離

    dx2,            // 計算坐標的臨時變量

    dy2, 

    x_inc,          // inc表示點的“生長方向” x_inc>1代表從左向右

    y_inc,          // inc表示點的“生長方向” x_inc>1代表從上向下(左上角是坐標原點)

    error,          // 由于坐標點只有整數,是離散的不是連續的,需要變量用于四舍五入的計算

    index;         

LCD_SetXY(x0,y0);

dx = x1-x0;//計算x距離

dy = y1-y0;//計算y距離


if (dx>=0)

{

x_inc = 1;

}

else

{

x_inc = -1;

dx    = -dx;  

if (dy>=0)

{

y_inc = 1;

else

{

y_inc = -1;

dy    = -dy; 


dx2 = dx << 1; //相當于乘以2,如此一來,四舍五入的誤差就變成了不到1舍,大于1入

dy2 = dy << 1;


if (dx > dy)//x距離大于y距離,那么對于每個x軸上只有一個點,每個y軸可能只有半個點

{

error = dy2 - dx; 

for (index=0; index <= dx; index++)//要畫的點數不會超過x距離

{

LCD_DrawPoint(x0,y0,Color);

if (error >= 0) //如果error>0 說明真實的y的誤差>0.5了,實際上應該+1了

{

error-=dx2;

y0+=y_inc;//增加y坐標值

error+=dy2;

x0+=x_inc;//x坐標值每次畫點后都遞增1

}

else

{

error = dx2 - dy; 

for (index=0; index <= dy; index++)

{

LCD_DrawPoint(x0,y0,Color);

if (error >= 0)

{

error-=dy2;

x0+=x_inc;

error+=dx2;

y0+=y_inc;

}


??由于界面中,我們常常需要劃一個方框,或者稱之為“按鈕”,所以我又封裝了一個函數:


/**

  * @brief 畫一個方框,或者稱之為按鈕

  * @param 方框左上角和右下角的點的坐標,顏色

* @note  右邊和下邊的線自帶加粗效果  如需花在屏幕最邊緣無加粗效果

  * @retval None

  */

void LCD_DrawBTN(u16 x1,u16 y1,u16 x2,u16 y2,u16 Color)

{

LCD_DrawLine(x1,  y1,  x2,y1, Color); //H

LCD_DrawLine(x1,  y1,  x1,y2, Color); //V

LCD_DrawLine(x1+1,y2-1,x2,y2-1, Color);  //H 加粗 多畫一條線

LCD_DrawLine(x1,  y2,  x2,y2, Color);  //H

LCD_DrawLine(x2-1,y1+1,x2-1,y2, Color);  //V

  LCD_DrawLine(x2  ,y1  ,x2,y2, Color); //V

}


顯示純色背景與圖片

??我們已經做到了全屏顯示,那么純色背景的顯示就很簡單了:


/**

  * @brief 全屏顯示純色圖片,可用作清屏

  * @param 顏色

  * @retval None

  */

void LCD_BG_Color(u16 color)

{

int i=16384;//128*128

  Full_Screen();

while(i-->0)//不可使用無符號數據類型

LCD_WD_U16(color);

}


??一共有16384個像素,那就調用16384次畫點的程序。只不過這里我稍作了一點優化,不用再管點的坐標了,因為已經設置了顯示區域是全屏。

??我專門寫了一個函數,顯示各個純色圖片,可以看出有沒有那個像素點顏色顯示的不全:


/**

  * @brief LCD屏幕測試,依次顯示純色照片,可以看出屏幕的每一個像素點是否正常

  * @param 每種顏色持續的時間,單位ms 

  * @retval None

  */

void LCD_Test(u16 delay_Time)

{

LCD_BG_Color(BLACK);

HAL_Delay(delay_Time);

LCD_BG_Color(RED);

HAL_Delay(delay_Time);

LCD_BG_Color(GREEN);

HAL_Delay(delay_Time);

LCD_BG_Color(BLUE);

HAL_Delay(delay_Time);

LCD_BG_Color(WHITE);

HAL_Delay(delay_Time);

}


??顯示全屏幕的背景圖片跟純色背景思路類似,把數據的來源改為數組就好:


/**

  * @brief 在LCD屏幕中顯示一個全屏的背景圖片

  * @param 無

* @note  只適用于128*128的屏幕,為了效率把長度直接計算了出來

  *        由于圖片數組要放在ROM,所以用了const,因此要做強制類型轉化(u8 *)

*        如果是雙工,則收發需要同一個數組,數組不能放在ROM

  * @retval None

  */

void LCD_BG_Image(void)

{

uint32_t i=32768; //Z144_HEIGHT*Z144_WIDTH*2;

  Full_Screen();

LCD_WD_buf((u8 *)LCD_MOTOR,i);

}


??接下來就是指定區域顯示圖片了,函數也很簡單:


/**

  * @brief 按照指定的坐標顯示圖片

  * @param 圖片左上角的坐標與右下角的坐標,圖片地址

* @note  圖片大小與坐標必須對應

  *        由于圖片數組要放在ROM,所以用了const,因此要做強制類型轉化(u8 *)

*        坐標范圍[0,127]

  * @retval None

  */

void LCD_Show_Image(u16 x0, u16 y0,u16 x1,u16 y1,const unsigned char *p)

{

int i = (x1-x0)*(y1-y0)*2;

LCD_SetArea(x0,y0,x1,y1);

LCD_WD_buf((u8 *)p,i);

}


??那么圖片數組從哪里來?

??取模得到。我去網上隨便找了一張彩圖,然后把尺寸編輯為100* 100像素。取模軟件如下設置:

在這里插入圖片描述

??然后可以得到圖片轉化為的數組。

顯示文字與字符

??中文字符都采用GBK(或者說GB2312)編碼,英文字符采用ASCII碼。顯示文字其實與顯示圖片的原理是一樣一樣的,思路在我另一篇博客中介紹過。

??先說漢字的取模設置:

在這里插入圖片描述

??我使用了結構體儲存漢字,結構體的每個元素都包含文字(或者稱之為索引)和它對應的編碼。因此得到的數組要稍加修改,增加雙引號與漢字,例如北京:


//修改前

0x04,0x40,0x04,0x40,0x04,0x40,0x04,0x44,0x04,0x48,0x7C,0x50,0x04,0x60,0x04,0x40,

0x04,0x40,0x04,0x40,0x04,0x40,0x04,0x42,0x1C,0x42,0xE4,0x42,0x44,0x3E,0x04,0x00,/*"北",4*/

0x02,0x00,0x01,0x00,0xFF,0xFE,0x00,0x00,0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,

0x10,0x10,0x1F,0xF0,0x01,0x00,0x11,0x10,0x11,0x08,0x21,0x04,0x45,0x04,0x02,0x00,/*"京",5*/

//修改后

"北",0x04,0x40,0x04,0x40,0x04,0x40,0x04,0x44,0x04,0x48,0x7C,0x50,0x04,0x60,0x04,0x40,

0x04,0x40,0x04,0x40,0x04,0x40,0x04,0x42,0x1C,0x42,0xE4,0x42,0x44,0x3E,0x04,0x00,/*"北",4*/

"京",0x02,0x00,0x01,0x00,0xFF,0xFE,0x00,0x00,0x00,0x00,0x1F,0xF0,0x10,0x10,0x10,0x10,

0x10,0x10,0x1F,0xF0,0x01,0x00,0x11,0x10,0x11,0x08,0x21,0x04,0x45,0x04,0x02,0x00,/*"京",5*/


??顯示的字符要先判斷是中文的還是英文的。英文字符的值小于128,顯示函數如下:


/**

  * @brief 輸出16*16的漢字或8*16的字符,函數可以自動識別是中文字符還是ASCII

  * @param 第一個字符的坐標,漢字顏色,背景顏色,需要顯示的字符串。背景顏色為0表示不畫背景

  * @retval None

  */

void LCD_DrawFont_GBK16(u16 x, u16 y, u16 fc, u16 bc, u8 *s)

{

unsigned char i,j;

unsigned short k,x0;

x0=x;

while(*s) 

{

if((*s) < 128)        //如果是ASCII碼,那么編號小于128

{

k=*s;

if (k==13)        //回車

{

x=x0;//記錄本行第一個字符的位置

y+=16;

}

else 

{

if (k>32) k-=32; else k=0;      //ASCII前32個都不是字符,除了回車,對顯示沒有影響,所以字庫不儲存

  for(i=0;i<16;i++)

{

for(j=0;j<8;j++) 

{

if(ASC16[k*16+i]&(0x80>>j)) //如有數據,畫字體  從高位到低位取出字符

[1] [2]
關鍵字:STM32  HAL庫  SPI驅動  TFTLCD 引用地址:STM32HAL庫使用SPI驅動1.44寸TFTLCD

上一篇:STM32自帶GB2312字庫顯示漢字
下一篇:STM32掌機教程9,完成掌機

推薦閱讀

隨著全球應對氣候變化意識的增強,新能源汽車在交通領域日漸流行起來。然而近日,美國官方公布的信息卻顯示,新能源汽車在美國的銷售情況并不理想,市場競爭力仍不及傳統化石燃料汽車。?據報道,美國能源信息署(EIA)最新發布報告稱,2017年,新能源汽車銷售量只占全美汽車市場份額的4%。?EIA指出,其統計的新能源汽車包括眾多種類,除大眾熟知的純電...
5月30日,深圳市友悅機器人科技有限公司(簡稱友悅)在深圳福田深航國際酒店發布了公司旗下新品友悅寶X15兒童機器人。活動當天,匯集了來自各地的友悅合作伙伴和寶媽寶爸群體用戶,現場賓朋滿座,熱鬧非凡。友悅還貼心在現場設立了入場禮和抽獎活動,每位入場嘉賓都滿載而歸。(排隊等待入場的來賓)(現場座無虛席)(友悅活動現場體量巨大的現場好禮)友...
協作機器人夾爪制造商OnRobot推出2.5D視覺系統Eyes,適用于各家先進機器手臂,提供外加的深度感知和零件辨識功能。 據報導,機器手臂經常遇到的難題,就是無法拾放大小、形狀或擺放方向不一的物品,通常需要外加夾具、送料盤等其它硬件協助作業,但也因此增加作業成本和復雜度,局限了設備的應用范圍。 OnRobot新推出的2.5D視覺系統Eyes,只要照一張...
5月31日,蘋果宣布大中華區的開發者社區規模日益龐大,目前已擁有超過 440 萬注冊開發者,與兩年前相比增長了 76%。蘋果表示,不斷涌現的中國開發者加入 Apple Developer Program,通過獲取先進的 Apple 技術,打造引人入勝的 app 體驗,并在全球市場大放異彩。同時,蘋果在 2021 年 1 月 1 日正式啟動的 App Store 小型企業計劃,給予...

史海拾趣

問答坊 | AI 解惑

項目設計:傳送帶速度測量

要求是在傳送帶的2端分別放置光電傳感器,中間用4個“7劃數碼管”(就是電子顯示的那個8)顯示傳送帶的速度 需要自行安裝排布所有的電路并分析 我們已完成光電傳感器的電路 問題在于如何使光電傳感器的輸出電壓作為測量速度的開始和結束?(需自 ...…

查看全部問答∨

漏電保護開關的正確選用與運行維護

漏電保護開關的正確選用與運行維護 http://www.iacmall.com/news-4-2622.html 或下載附件…

查看全部問答∨

為什么藍牙模塊對HCI命令沒反應啊?

我最近在做一塊ARM板上的藍牙底層初始化驅動,環境如下 板子:ARM11板 Linux內核版本:2.6.18 藍牙模塊:采用CSR的Bluecore5核心,和CPU通過UART相連 藍牙驅動:1.自己根據藍牙的datasheet在系統啟動時給藍牙模塊發送了一條Reset信號,并初始化 ...…

查看全部問答∨

求購或訂做windows CE下智能輸入法

求購windows CE下智能輸入法,最好是T9輸入法,至少含拼音和筆畫,windows CE操作系統,鍵盤4X5。有意聯系xiao615@126.com.…

查看全部問答∨

SHLoadImageFile函數

我想打開png圖片,上網查到要用SHLoadImageFile函數可以,但是使用SHLoadImageFile函數需要aygshell.lib,我在網上找不到aygshell.lib,卻下載了AYGSHELL.DLL,可是光有AYGSHELL.DLL卻不知道應該怎么用它。 希望高人指點一下怎么用AYGSHELL.DLL來 ...…

查看全部問答∨

卡車也要有能“耐”我來曬曬中國勒芒輕卡耐力賽PP

早晨起來,一看上海天馬上賽車場已經裝扮一新,賽道內有專門的維修通道,與正式的F1比賽管理別無二致,已悄然感受到大戰的氣息。在賽事現場,熱辣的美女、轟鳴的馬達、絢麗的奧鈴CTX賽車、激情吶喊的觀眾,這就是2010(第二屆)福田奧鈴CTX中國勒芒 ...…

查看全部問答∨

【MSP430共享】最全電子書收集

請大家更貼完善 [ 本帖最后由 fengzhang2002 于 2011-9-7 12:13 編輯 ]…

查看全部問答∨

AM335x ADC Driver's Guide ADC驅動中文手冊改1

AM335x ADC Driver\'s Guide ADC驅動中文手冊改1…

查看全部問答∨

28335的AD采樣?

在做AD采樣時,初始化AD時,如果沒有這段代碼,發現采樣結果不對,加上后,檢測結果正常:         AdcRegs.ADCTRL1.bit.RESET=1; //復位整個ADC模塊         DSP28x_usDelay(1);      ...…

查看全部問答∨

什么是PCB設計DSP及DSP技術詳解

  數字信號處理(Digital Signal Processing,簡稱PCB設計DSP)是一門涉及許多學科而又廣泛應用于許多領域的新興學科。   介紹PCB設計DSP的歷史以及一些基礎參數,目前,TI公司是最大的PCB設計DSP生產商.   20世紀60年代以來,隨著計算機 ...…

查看全部問答∨
小廣播
設計資源 培訓 開發板 精華推薦

最新單片機文章
何立民專欄 單片機及嵌入式寶典

北京航空航天大學教授,20余年來致力于單片機與嵌入式系統推廣工作。

 
EEWorld訂閱號

 
EEWorld服務號

 
汽車開發圈

 
機器人開發圈

電子工程世界版權所有 京ICP證060456號 京ICP備10001474號-1 電信業務審批[2006]字第258號函 京公網安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
主站蜘蛛池模板: 巴楚县| 会东县| 桃江县| 林甸县| 岚皋县| 临洮县| 闽清县| 收藏| 长春市| 繁昌县| 襄樊市| 当雄县| 潞城市| 肥东县| 黑龙江省| 奈曼旗| 东兴市| 察雅县| 瓦房店市| 三门县| 海南省| 祁连县| 宁晋县| 喀喇沁旗| 阿鲁科尔沁旗| 舟山市| 咸丰县| 濮阳县| 余庆县| 高陵县| 思南县| 壤塘县| 北流市| 涟水县| 南和县| 万盛区| 永修县| 胶州市| 缙云县| 墨竹工卡县| 崇明县|