1. 程式人生 > >stm32的LCD螢幕顯示+各個模組功能除錯

stm32的LCD螢幕顯示+各個模組功能除錯

從PWM輸出實驗的工程開始,加入其他各種功能。

LCD螢幕顯示:

一、hardware
這裡寫圖片描述
其中timer是產生脈衝的。
二、hallib
這裡寫圖片描述
FMC是一個介面,控制SDRAM和LCD
三、#include

#include "lcd.h"
#include "sdram.h"

四、init()
SDRAM_Init(); //初始化SDRAM
LCD_Init(); //LCD初始化

這裡寫圖片描述
這兩個初始化是關鍵部分,首先SDRAM_Init(); 是SDRAM的底層驅動檔案,LCD_Init();中會呼叫ltdc_init(),還會用到HAL_SDRAM_Init

USMART除錯:

1.包含USMART資料夾以及它的path(不是hardware,麼有hallib)
2.#include “usmart.h”
3.usmart_dev.init(108); //初始化USMART
4.usmart_config.c中,包含timer.h,在新增函式的地方新增TIM3_PWM_Init函式即可
這裡寫圖片描述
5.開啟串列埠除錯助手直接傳送TIM3_PWM_Init(999,107),同時可以隨時更改舵機的轉動角度。
這裡寫圖片描述

RTC時鐘:

1.hardware
rtc資料夾
2.hallib
stm32f7xx_hal_rtc.c
stm32f7xx_hal_rtc_ex.c
3.include
rtc.h
4.main

RTC_TimeTypeDef RTC_TimeStruct;
    RTC_DateTypeDef RTC_DateStruct;
    u8 tbuf[40];
    u8 t=0;
RTC_Init();                     //初始化RTC
t++;
        if((t%10)==0)   //每100ms更新一次顯示資料
        {
            HAL_RTC_GetTime(&RTC_Handler,&RTC_TimeStruct,RTC_FORMAT_BIN);
            sprintf((char*)tbuf,"Time:%02d
:%02d:%02d"
,RTC_TimeStruct.Hours,RTC_TimeStruct.Minutes,RTC_TimeStruct.Seconds); LCD_ShowString(30,140,210,16,16,tbuf); HAL_RTC_GetDate(&RTC_Handler,&RTC_DateStruct,RTC_FORMAT_BIN); sprintf((char*)tbuf,"Date:20%02d-%02d-%02d",RTC_DateStruct.Year,RTC_DateStruct.Month,RTC_DateStruct.Date); LCD_ShowString(30,160,210,16,16,tbuf); sprintf((char*)tbuf,"Week:%d",RTC_DateStruct.WeekDay); LCD_ShowString(30,180,210,16,16,tbuf); }

5.usmart
這裡寫圖片描述
6.rtc.c中
中斷處理回撥函式:

#include "timer.h"
//RTC鬧鐘A中斷處理回撥函式
void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{
    printf("ALARM A!\r\n");
    TIM3_PWM_Init(1000*-1,108-1);
}

待機喚醒:

1.hardware
wkup
2.hallib

3.include

#include "wkup.h"

4.main
WKUP_Init(); //待機喚醒初始化
LCD_Init(); //初始化LCD
LCD_Init必須要在WKUP_Init之後,每次點選按鍵都會進入到main函式中,那麼都會進入到WKUP_Init():

//WKUP_Init:
    if(Check_WKUP()==0)
    {
        Sys_Enter_Standby();//不是開機,進入待機模式
    }
//按鍵中斷:
    if(Check_WKUP())//關機
        {
            Sys_Enter_Standby();//進入待機模式
        }

假如按下沒有3秒,就直接Check_WKUP()==0進入待機;假如按下有3秒,跳過了Sys_Enter_Standby()可以正常開機,同時開啟按鍵中斷。如果開機後按下沒有3秒,進入中斷判斷就不會進入Sys_Enter_Standby();如果開機後按下有3秒,直接進入待機。

TPAD:

1.hardware
tpad
2.hallib

3.include

#include "tpad.h"

4.main

TPAD_Init(8);                   //初始化觸控按鍵,以108/8=13.5Mhz頻率計數
 switch (TPAD_Scan(0))            //成功捕獲到了一次上升沿(此函式執行時間至少15ms)
        {
            case 0:
                LCD_LED(1);   //開背光
                LED1(1);
                break;
            case 1:
                LCD_LED(0);   //關背光
                LED1(0);
                break;
        }
switch (TPAD_Scan(0)) 在while1)裡面迴圈。

5.tpad.c

u8 TPAD_Scan(u8 mode)
{
    static u8 keyen=0;  //0,可以開始檢測;>0,還不能開始檢測    
    static u8 res=0;
    u8 sample=3;        //預設取樣次數為3次  
    u16 rval;
    if(mode)
    {
        sample=6;   //支援連按的時候,設定取樣次數為6次
        keyen=0;    //支援連按    
    }
    rval=TPAD_Get_MaxVal(sample); 
    if(rval>(tpad_default_val*4/3)&&rval<(10*tpad_default_val))//大於tpad_default_val+TPAD_GATE_VAL,且小於10倍tpad_default_val,則有效
    {                            
        if(keyen==0)res++;  //大於tpad_default_val+TPAD_GATE_VAL,有   
        //printf("r:%d\r\n",rval);                                         
        keyen=3;                //至少要再過3次之後才能按鍵有效   
    } 
    if(keyen)keyen--;
    res=res%2;
    return res;
}

首先預設的是time2的通道1,gpio是pa5,然而pa5會和後面的ADC衝突,所以選擇time2的通道3,gpio是pa2。
更改GPIO_PIN_2、TIM_CHANNEL_3即可,GPIO_AF1_TIM2不用管。

ADC:

1.hardware
ADC
2.hallib
adc.c以及adc_ex.c
3.main

#include“adc.h”
u16 adcx;float temp;
MY_ADC_Init();                  //初始化ADC1通道
adcx=Get_Adc_Average(ADC_CHANNEL_5,20);//獲取通道5的轉換值,20次取平均
        LCD_ShowxNum(134,130,adcx,4,16,0);    //顯示ADCC取樣後的原始值
        temp=(float)adcx*(3.3/4096);          //獲取計算後的帶小數的實際電壓值,比如3.1111
        adcx=temp;                            //賦值整數部分給adcx變數,因為adcx為u16整形
        LCD_ShowxNum(134,150,adcx,1,16,0);    //顯示電壓值的整數部分,3.1111的話,這裡就是顯示3
        temp-=adcx;                           //把已經顯示的整數部分去掉,留下小數部分,比如3.1111-3=0.1111
        temp*=1000;                           //小數部分乘以1000,例如:0.1111就轉換為111.1,相當於保留三位小數。
        LCD_ShowxNum(150,150,temp,3,16,0X80); //顯示小數部分(前面轉換為了整形顯示),這裡顯示的就是111.

在內部溫度感測器時為short temp。
4.驅動檔案

ADC1_Handler.Init.Resolution=ADC_RESOLUTION_12B;             //12位模式

GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1時鐘
    __HAL_RCC_GPIOA_CLK_ENABLE();           //開啟GPIOA時鐘

    GPIO_Initure.Pin=GPIO_PIN_5;            //PA5
    GPIO_Initure.Mode=GPIO_MODE_ANALOG;     //模擬
    GPIO_Initure.Pull=GPIO_NOPULL;          //不帶上下拉
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);

Get_Adc_Average(ADC_CHANNEL_5,20)是要得到通道5的值,所以要初始化PA5,假如是內部溫度感測器,它是接的通道18,就不用管PA5,HAL_ADC_MspInit中只用使能ADC1時鐘即可,Get_Temprate函式會得到通道18的電壓值,temperate=(float)adcx*(3.3/4096);預設的參考電壓都是0-3.3V,而12位的解析度,通道里面得到的是數字,經過轉換就可以得到對應的電壓。

DAC:

1.hardware
DAC
2.hallib
dac.c以及dac_ex.c
3.main

#include "dac.h"
u16 dacval=0;u8 key;
DAC1_Init();                    //初始化DAC1
LCD_ShowString(30,150,200,16,16,"DAC VAL:");          
    LCD_ShowString(30,170,200,16,16,"DAC VOL:0.000V");        
    LCD_ShowString(30,190,200,16,16,"ADC VOL:0.000V");
key=KEY_Scan(0);              
        if(key==KEY2_PRES)
        {        
            if(dacval<4000)dacval+=200;
            HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,dacval);//設定DAC值
        }else if(key==KEY1_PRES)    
        {
            if(dacval>200)dacval-=200;
            else dacval=0;
            HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,dacval);//設定DAC值
        }    
        if(t==10||key==KEY1_PRES||key==KEY2_PRES)       //WKUP/KEY1按下了,或者定時時間到了
        {     
            adcx=HAL_DAC_GetValue(&DAC1_Handler,DAC_CHANNEL_1);//讀取前面設定DAC的值
            LCD_ShowxNum(94,150,adcx,4,16,0);           //顯示DAC暫存器值
            temp=(float)adcx*(3.3/4096);                //得到DAC電壓值
            adcx=temp;
            LCD_ShowxNum(94,170,temp,1,16,0);           //顯示電壓值整數部分
            temp-=adcx;
            temp*=1000;
            LCD_ShowxNum(110,170,temp,3,16,0X80);       //顯示電壓值的小數部分
            adcx=Get_Adc_Average(ADC_CHANNEL_5,10);     //得到ADC轉換值    
            temp=(float)adcx*(3.3/4096);                //得到ADC電壓值
            adcx=temp;
            LCD_ShowxNum(94,190,temp,1,16,0);           //顯示電壓值整數部分
            temp-=adcx;
            temp*=1000;
            LCD_ShowxNum(110,190,temp,3,16,0X80);       //顯示電壓值的小數部分       
            t=0;
        }       
        delay_ms(10);

4.驅動檔案
PA4作為DAC的輸出通道,先用按鍵控制給它一個數字,這個數字放到了DAC通道,放到DAC通道的訊號是數字訊號,然後讀取DAC通道的值就是一個數字,將數字轉換為對應的模擬電壓(0-3300對應0-3.3V),這時可以讀取出通道1的值進行轉換得到模擬電壓。

PA4和PA5用跳線帽相接,PA5作為ADC的輸入通道,放到ADC通道的訊號是模擬訊號,然後讀取通道的值就是一個模擬數字,轉換為對應的數字電壓(0-3300對應0-3.3V),再進行轉換後得到一個數字電壓的值。

pcf8574:

PCF8574是一個IO口的擴充套件晶片,2個io最多可以擴充套件64個io口。
1.hardware
IIC以及PCF8574
2.hallib

3.main

#include "pcf8574.h"
u8 beepsta=1;    //pcf8574
PCF8574_Init(); //初始化PCF8574
if(key==KEY0_PRES)//KEY0按下,讀取字串並顯示
        { 
            beepsta=!beepsta;                   //蜂鳴器狀態取反
            PCF8574_WriteBit(BEEP_IO,beepsta);  //控制蜂鳴器
        }
        if(PCF8574_INT==0)              //PCF8574的中斷低電平有效
        {
            key=PCF8574_ReadBit(EX_IO); //讀取EXIO狀態,同時清除PCF8574的中斷輸出(INT恢復高電平)
            if(key==0)LED0_Toggle;      //LED1狀態取反 
        }

判斷PCF8574_INT是為了分時複用,將EX_IO與一個低電平反覆觸碰的話就會觸發PCF8574的中斷。

4.驅動檔案

IIC_Init(); 
同時初始化PB12(PCF8574的INT腳與stm32f767的PB12相接)為上拉輸入;
將全部io置為高電平。

觸控式螢幕:

1.hardware
24CXX以及touch
2.hallib

3.main

#include "touch.h"
u8 t1=0;u16 lastpos[5][2];       //觸控式螢幕
tp_dev.init();                  //觸控式螢幕初始化 
tp_dev.scan(0);
            if(tp_dev.sta)
            {
                if(tp_dev.x[t1]<lcddev.width&&tp_dev.y[t1]<lcddev.height)
                {
                    if(0<tp_dev.x[0]&&tp_dev.x[0]<60&&250<tp_dev.y[0]&&tp_dev.y[0]<350)
                    {
                    LED0_Toggle;//清除
                    PCF8574_WriteBit(BEEP_IO,0);    //控制蜂鳴器 
                    delay_ms(50);
                    PCF8574_WriteBit(BEEP_IO,1);    //控制蜂鳴器     
                    }
                }
            }
        }

就是不用5點觸控,直接一有觸控馬上就反應。假設要畫一個按鍵控制舵機轉動的話可以參照下圖:
這裡寫圖片描述
4.驅動檔案

u8 FT5206_Scan(u8 mode)中也去掉了5點觸控的判斷。

紅外遙控:

1.hardware
remote
2.hallib

3.main

#include "remote.h"
Remote_Init();                  //初始化   紅外接收    
key=Remote_Scan();  
        if(key)
        {
        LCD_ShowNum(86,130,key,3,16);       //顯示鍵值
        LCD_ShowNum(86,150,RmtCnt,3,16);    //顯示按鍵次數          
            switch(key)
            {
                case 0:str="ERROR";break;              
                case 162:str="POWER";break;     
                case 98:str="UP";break;     
                case 2:str="PLAY";break;         
                case 226:str="ALIENTEK";break;        
                case 194:str="RIGHT";break;    
                case 34:str="LEFT";break;         
                case 224:str="VOL-";break;        
                case 168:str="DOWN";break;         
                case 144:str="VOL+";break;          
                case 104:str="1";TIM3_PWM_Init(1000-1,108-1);break;       
                case 152:str="2";TIM3_PWM_Init(2000-1,108-1);break;    
                case 176:str="3";TIM3_PWM_Init(3000-1,108-1);break;     
                case 48:str="4";TIM3_PWM_Init(4000-1,108-1);break;          
                case 24:str="5";TIM3_PWM_Init(5000-1,108-1);break;          
                case 122:str="6";break;       
                case 16:str="7";break;                              
                case 56:str="8";break;   
                case 90:str="9";break;
                case 66:str="0";break;
                case 82:str="DELETE";break;      
            }
        }else delay_ms(10);  
        LCD_Fill(86,170,86+8*8,170+16,WHITE);   //清之前的顯示
        LCD_ShowString(86,170,200,16,16,str);   //顯示SYMBOL

這裡注意一定要判斷if(key),不然一直瘋狂重新整理介面。
4.驅動檔案
紅外遙控也是輸入捕獲,用的是定時器1的通道1,所以和pwm的定時器3不衝突。
這裡寫圖片描述

FLASH:

1.hardware
STMFLASH
2.hallib
flash/flash.ex
3.main

#include "stmflash.h"
//要寫入到STM32 FLASH的字串陣列
const u8 TEXT_Buffer[]={"STM32 FLASH TEST"};
#define TEXT_LENTH sizeof(TEXT_Buffer)              //陣列長度  
#define SIZE TEXT_LENTH/4+((TEXT_LENTH%4)?1:0)

#define FLASH_SAVE_ADDR  0X08020000     //設定FLASH 儲存地址(必須為4的倍數,且所在扇區,要大於本程式碼所佔用到的扇區.
                                        //否則,寫操作的時候,可能會導致擦除整個扇區,從而引起部分程式丟失.引起宕機.

u8 datatemp[SIZE]; 
LCD_ShowString(30,170,200,16,16,"Start Write FLASH....");
            STMFLASH_Write(FLASH_SAVE_ADDR,(u32*)TEXT_Buffer,SIZE);
            LCD_ShowString(30,170,200,16,16,"FLASH Write Finished!");//提示傳送完成

STMFLASH_Read(FLASH_SAVE_ADDR,(u32*)datatemp,SIZE);
            LCD_ShowString(30,170,200,16,16,"The Data Readed Is:  ");//提示傳送完成
            LCD_ShowString(30,190,200,16,16,datatemp);//顯示讀到的字串

FLASH:

1.hardware
STMFLASH
2.hallib
flash/flash.ex
3.main