STM32實戰應用(一)——1602藍牙時鍾1液晶的顯示測試


前言

從51到STM32F4學習這么久了,總算找到點頭緒了,目前學習了GPIO,中斷,定時器,看門狗的基本使用,所以想試着看看能不能做個什么東西,就是想復習一下最近學習的知識。正好上學期單片機課程設計做過一個可以藍牙、按鍵校准、帶溫度顯示的時鍾,所以我想看能不能將程序移植到STM32上呢?說做就做,經過三天的時間,幾次的程序修改和調試,終於成功了!

關於51單片機實現的時鍾可以參考我以前發表的博文,里面還有演示的視頻鏈接

由於STM32內部定時器的精度還是很高的(一小時慢1s),所以就沒有使用DS1302時鍾芯片(關鍵是手里沒有),顯示上和課程設計做的有些不一樣,沒有增加日期和星期顯示,就時間、鬧鍾和溫度的顯示。 

今天先學習一下1602液晶的顯示,那么如何用STM32控制LCD1602顯示字符,字符串或數字呢?

1602液晶介紹

工業字符型液晶,能夠同時顯示16x02即32個字符。1602液晶也叫1602字符型液晶,它是一種專門用來顯示字母、數字、符號等的點陣型液晶模塊。它由若干個5X7或者5X11等點陣字符位組成,每個點陣字符位都可以顯示一個字符,每位之間有一個點距的間隔,每行之間也有間隔,起到了字符間距和行間距的作用,正因為如此所以它不能很好地顯示圖形(用自定義CGRAM,顯示效果也不好)。市面上字符液晶大多數是基於HD44780液晶芯片的,控制原理是完全相同的,因此基於HD44780寫的控制程序可以很方便地應用於市面上大部分的字符型液晶。1602LCD是指顯示的內容為16X2,即可以顯示兩行,每行16個字符液晶模塊(顯示字符和數字)。

由於1602液晶是5V供電,引腳高電平為5v。不像51單片機IO輸出高電平5v,STM32高電平只有3.3v,低電平0v,找到了1602的數據手冊,里面居然沒有說明高電平電壓范圍,到底能不能驅動呢?我又查找了1602驅動芯片HD44780的數據手冊,其中有一個電壓特性,如下圖

可見用STM32的3.3v電平驅動顯示完全沒問題,看到這我就放心了,代碼經過多次的修改后,終於成功顯示了,所以還是要多看看數據手冊。

硬件電路連接

 

 

程序設計

1.控制線宏定義,通過位帶操作,以后就可以像51那樣RS=1來操作了,是不是很熟悉呢?這里還將數據線的8個端口定義為了一個LCD_DB

#define LCD_RS PAout(1)
#define LCD_RW PAout(4)
#define LCD_EN PAout(6)
#define LCD_DB GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 |GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15

2.LCD相連的GPIO配置,將數據線端口配置為OD(開漏)輸出模式,可以做雙向IO使用,在檢測LCD是否忙時,需要讀取D7位的狀態

void LCD_GPIO_Config(void)
{
    GPIO_InitTypeDef  IO_Init;
    
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA | RCC_AHB1Periph_GPIOE,ENABLE);
    
    /*控制線初始化 : */
    IO_Init.GPIO_Mode=GPIO_Mode_OUT;        //輸出
    IO_Init.GPIO_OType=GPIO_OType_PP;        //推挽模式
    IO_Init.GPIO_Pin=GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_6; 
    IO_Init.GPIO_PuPd=GPIO_PuPd_UP;            //
    IO_Init.GPIO_Speed=GPIO_Speed_2MHz;        //GPIO_Speed_2MHz
    GPIO_Init(GPIOA,&IO_Init);
    
    /*數據線初始化*/
    IO_Init.GPIO_Mode=GPIO_Mode_OUT;
    IO_Init.GPIO_OType=GPIO_OType_OD;        //開漏輸出可雙向
    IO_Init.GPIO_Pin=LCD_DB;
    IO_Init.GPIO_PuPd=GPIO_PuPd_UP;            //上拉
    IO_Init.GPIO_Speed=GPIO_Speed_2MHz;        
    GPIO_Init(GPIOE,&IO_Init);                        
    /*測試 : 高電平3.3v
    LCD_RS=1;
    LCD_RW=1;
    LCD_EN=1;
    GPIO_SetBits(GPIOE,LCD_DB); */
}

 

3.實現P1=0xff功能的函數,帶參數

void GPIO_OutData(u8 Dat)
{
    u16 tmp;
    tmp = 0;
    tmp =Dat;
    tmp <<= 8;            //數據左移到高8位
    GPIO_Write(GPIOE,tmp);        //數據寫入到GPIOE高8位
}

4.檢測LCD是否忙

void LCD_CheckBusy(void)
{
    u8 sta;
    GPIO_OutData(0xff);
    LCD_RS=0;
    LCD_RW=1;
    do{
        LCD_EN=1;
        delay_ms(5);
        sta = GPIO_ReadInputDataBit(GPIOE,GPIO_Pin_15);
        LCD_EN =0;
    }while(sta & 0x80);
}

 

5.向LCD寫一字節數據

/* LCD_RS = 1, LCD_RW = 0 */
void LCD_WriteData(u8 Dat)
{

    LCD_CheckBusy(); //忙則等待
    LCD_RS=1;
    LCD_RW=0;
    GPIO_OutData(Dat);
    LCD_EN=1;
    delay_ms(1);
    LCD_EN = 0;
    
}

 6.向LCD寫一字節命令

/*LCD_RS = 0, LCD_RW = 0*/
void LCD_WriteCmd(u8 Cmd)
{
    LCD_CheckBusy(); //忙則等待
    LCD_RS = 0;
    LCD_RW = 0;
    GPIO_OutData(Cmd);    
    LCD_EN = 1;
    delay_ms(1);
    LCD_EN = 0;     
}

 

7.LCD初始化

void LCD_Init(void)
{
    LCD_WriteCmd(0x38);
    LCD_WriteCmd(0x0C);
    LCD_WriteCmd(0x06);    /*顯示光標移動設置*/    delay_ms(1);
    LCD_WriteCmd(0x01);    /*顯示清屏*/
}

8.LCD清屏

void LCD_ClearScrren(void)
{
    LCD_WriteCmd(0x01);
}

 

9.根據xy坐標,寫入對應的數據位置

void LCD_SetCursor(u8 x, u8 y)
{
    u8 addr;
    if (y == 0)
        addr = 0x00 + x;
    else
        addr = 0x40 + x;
    LCD_WriteCmd(addr | 0x80);
}

 10.根據xy坐標顯示一個字符

 
void LCD_DisChar(u8 x,u8 y,u8 ch)
{
    LCD_SetCursor(x,y);        //字符顯示位置設定
    LCD_WriteData(ch);
}

11.顯示兩位的數字

void LCD_DisNumber(u8 x,u8 y,u8 Num)
{
    LCD_SetCursor(x,y);
    LCD_WriteData(0x30+Num/10);
    LCD_SetCursor(x+1,y);
    LCD_WriteData(0x30+Num%10);
}

 

12.顯示字符串

void LCD_DisString(u8 x,u8 y,u8 *str)
{
    LCD_SetCursor(x, y);
    while(*str != '\0')
    {
        LCD_WriteData(*str++);
    }
}

 主函數

int main(void)
{
    delay_init(168);
    LED_Init();
    
    LCD_GPIO_Config();
    LCD_Init();
    LCD_ClearScrren();
    while(1)
    {
        delay_ms(500);
        LED1_ON;
        LCD_DisString(0,0,"abcdefghijklmnop");
        delay_ms(500);
        LED1_OFF;
        LCD_DisNumber(0,1,56);
        LCD_DisChar(2,1,'a');
        LCD_DisString(3,1," Hello World!");
    }    
}

 

實際顯示效果:

顯示非常完美,和51驅動沒有什么區別

總結:

實際運行時,不使用檢測忙函數也行,1602顯示正常了,接下來就是增加定時器顯示時鍾了。在設置IO口模式時,可以將模式設置為開漏模式,就可以實現雙向IO的目的,即可輸出,又可以讀取外部輸入。通過位帶操作和宏定義就可以像51那樣直接操作IO口輸出高低電平了。 

參考資料:

 
 程序源碼下載鏈接: https://pan.baidu.com/s/1hsvEBcg 密碼: fk3b

歡迎查看我以前的單片機學習筆記:

 
 
 
以上是我學習過程的一些個人理解,有不對或不准確的地方,歡迎各位大神指正。
 
2017年4月23日14:24:45
 歡迎大家關注 我的個人博客

微信掃碼關注我的公眾號

不定期更新個人學習筆記和技術總結,歡迎大家互相學習交流!

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM