本文例子用到:
1. STM32F072 Nucleo开发板
2. 12864液晶
3. STM32CubeMX软件Version4.3.0
4. Keil MDK 软件Version5.12.0.0
下面开始讲解:
首先讲一下思路。本文将MSP430单片机(16位)控制12864的程序移植到STM32F072控制12864。其实控制12864实际上就是对IO口进行写0或者写1的操作,不同单片机控制IO口输出0或1方法不同,比如MSP430将IO口置一为P1OUT|=BIT0;将IO口清零则为P1OUT~=BIT0;(此处是将MSP430的P10进行置一与清零);而STM32利用库函数将IO口置一为HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_SET);将IO清零则为HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13,GPIO_PIN_RESET);(此处是将STM32的PB13置一与清零);只需要将MSP430控制IO口的程序改为STM32控制IO口的程序就行,另外,由于不同单片机时钟频率不一样,运行速度不一样,因此可能需要改一下移植程序中的延时。(另外,IO口配置输入输出的方式也需要改)
12864液晶有并行和串行两种接线方式,本文采用串行控制。串行控制至少需要将液晶的三个IO口连到STM32的IO口。分别是片选信号CS(RS),数据信号SID(RW),时钟信号SCLK(E),PSB直接接到GND,RST可以不接。
接下来开始讲讲实际怎么操作。
1. 通过STM32CubeMX软件配置IO口。本文IO口接法:
PB13------------------CS(RS)
PB14------------------SID(RW)
PB15------------------SCLK(E)
GND-------------------PSB
GND-------------------VSS
+5V--------------------VDD
GND-------------------LEDK
+5V--------------------LEDA
STM32Cube配置如下:
2. STM32Cube其他配置默认,生成Keil工程。
3. 首先看看要移植的lcd12864程序:
#define uchar unsigned char #define uint unsigned int #define LCD12864_CS_OUT P1DIR|=BIT4 #define LCD12864_CS_H P1OUT|=BIT4 #define LCD12864_CS_L P1OUT&=~BIT4 #define LCD12864_SID_OUT P1DIR|=BIT2 #define LCD12864_SID_H P1OUT|=BIT2 #define LCD12864_SID_L P1OUT&=~BIT2 #define LCD12864_SCLK_OUT P1DIR|=BIT3 #define LCD12864_SCLK_H P1OUT|=BIT3 #define LCD12864_SCLK_L P1OUT&=~BIT3 //PSB由硬件置低,故省去 //#define LED12864_PSB_OUT P1DIR|=BIT5 //#define LED12864_PSB_L P1OUT&=~BIT5 //RST不接也行 //#define LCD12864_RST_OUT P1DIR|=BIT6 //#define LCD12864_RST_H P1OUT|=BIT6 //#define LCD12864_RST_L P1OUT&=~BIT6 /******************************************************************** * 名称 : delay() * 功能 : 软件延时 * 输入 : t * 输出 : 无 ***********************************************************************/ void delay(unsigned int t) { unsigned int i,j; for(i=0; i<t; i++) for(j=0; j<3; j++); } /******************************************************************** * 名称 : sendbyte() * 功能 : 按照液晶的串口通信协议,发送数据 * 输入 : zdata * 输出 : 无 ***********************************************************************/ void sendbyte(unsigned char zdata) { unsigned int i; for(i=0; i<8; i++) { if((zdata << i) & 0x80) { LCD12864_SID_H;//SID=1 } else { LCD12864_SID_L ; } LCD12864_SCLK_L;//SCLK = 0; LCD12864_SCLK_H;//SCLK = 1; } } /******************************************************************** * 名称 : write_com() * 功能 : 写串口指令 * 输入 : cmdcode * 输出 : 无 ***********************************************************************/ void write_com(unsigned char cmdcode) { LCD12864_CS_H ;//CS = 1; sendbyte(0xf8); sendbyte(cmdcode & 0xf0); sendbyte((cmdcode << 4) & 0xf0); delay(1); } /******************************************************************** * 名称 : write_data() * 功能 : 写串口数据 * 输入 : Dispdata * 输出 : 无 ***********************************************************************/ void write_data(unsigned char Dispdata) { LCD12864_CS_H ;//CS = 1; sendbyte(0xfa); sendbyte(Dispdata & 0xf0); sendbyte((Dispdata << 4) & 0xf0); delay(1); } /******************************************************************** * 名称 : init() * 功能 : 初始化函数 * 输入 : cmdcode * 输出 : 无 ***********************************************************************/ void lcd12864_init() { LCD12864_CS_OUT ; LCD12864_SID_OUT ; LCD12864_SCLK_OUT ; // LED12864_PSB_OUT ; // LCD12864_RST_OUT ; // LED12864_PSB_L; // LCD12864_RST_L;//RST = 0; // delay_ms(100); // LCD12864_RST_H;//RST = 1; // delay_ms(5); write_com(0x30); delay(2000); write_com(0x0c); delay(2000); write_com(0x01); } // *清除图像显示 void clearLCD(void) { uchar i, j; write_com(0x36); // 8位,扩充指令集,图形显示开 for (i = 0; i < 32; i++) // 32行,12864=25632 { write_com(0x80 + i); // 绘图区的Y地址 write_com(0x80); // 绘图区的X地址 for (j = 0; j < 32; j++) { write_data(0x00); // 清除 } } write_com(0x30); // 8位,基本指令集 } void pos(uchar x,uchar y) //*设定LCD写位置 { uchar pos; if(x==0) x=0x80; else if(x==1) x=0x90; else if(x==2) x=0x88; else if(x==3) x=0x98; pos=x+y; write_com(pos); }
4.上面的程序写的比较规范,IO口控制都是通过宏定义,我们只需要将
#define LCD12864_CS_OUT P1DIR|=BIT4 #define LCD12864_CS_H P1OUT|=BIT4 #define LCD12864_CS_L P1OUT&=~BIT4
改为
#define LCD12864_CS_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13,GPIO_PIN_SET) #define LCD12864_CS_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13,GPIO_PIN_RESET)
由于在STM32Cube中我们已经将对于IO口配置为输出,故
#define LCD12864_CS_OUT P1DIR|=BIT4可以不用理会。
其他IO配置相同。总的配置如下:
#define LCD12864_CS_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13,GPIO_PIN_SET) #define LCD12864_CS_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_13,GPIO_PIN_RESET) #define LCD12864_SID_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14,GPIO_PIN_SET) #define LCD12864_SID_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_14,GPIO_PIN_RESET) #define LCD12864_SCLK_H HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15,GPIO_PIN_SET) #define LCD12864_SCLK_L HAL_GPIO_WritePin(GPIOB, GPIO_PIN_15,GPIO_PIN_RESET)
再看看lcd12864初始化函数:
void lcd12864_init() { LCD12864_CS_OUT ; LCD12864_SID_OUT ; LCD12864_SCLK_OUT ; // LED12864_PSB_OUT ; // LCD12864_RST_OUT ; // LED12864_PSB_L; // LCD12864_RST_L;//RST = 0; // delay_ms(100); // LCD12864_RST_H;//RST = 1; // delay_ms(5); write_com(0x30); delay(2000); write_com(0x0c); delay(2000); write_com(0x01); }
由于我们在STM32Cube中已经将IO口设置为输出,故可以将
LCD12864_CS_OUT;
LCD12864_SID_OUT;
LCD12864_SCLK_OUT;
这三句删除。
5. 由于12864液晶对延时要求不是很严格,故此处不用改延时,如果出现问题,可以尝试改改延时程序。
6. 将修改好的程序放入生成的keil工程中,放在
/* USER CODE BEGIN 0 */与/* USER CODE END 0*/之间
7. 最后,写个小程序测试一下。
main函数如下:
int main(void) { /* USER CODE BEGIN 1 */ int i=0; unsigned char a[]="--Hello Nucleo!-"; unsigned char b[]="--Hello World!--"; unsigned char c[]="--Hello STMCU!--"; unsigned char d[]=" ~@^_^@~ "; /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* System interrupt init*/ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); /* Initialize all configured peripherals */ MX_GPIO_Init(); /* USER CODE BEGIN 2 */ lcd12864_init();//lcd12864液晶初始化 delay(10000);//适当延时 pos(0,0);//设置显示起始位置 for(i=0;i<16;i++)//设置显示内容 { write_data(a[i]); } pos(1,0); for(i=0;i<16;i++) { write_data(b[i]); } pos(2,0); for(i=0;i<16;i++) { write_data(c[i]); } pos(3,0); for(i=0;i<16;i++) { write_data(d[i]); } /* USER CODE END 2 */ /* USER CODE BEGIN 3 */ /* Infinite loop */ while (1) { } /* USER CODE END 3 */ }
显示效果如下:
HJL
2015.1.20