STM32F072笔记3-移植12864液晶程序
本文例子用到:
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