CCWO Embedded Space

CCWOの日々の開発を発信するブログ

STM32 F401RE LCDモジュール

開発環境
・評価ボード NUCLEO-F401RE
・IDE MDK-ARM V5 and STM32CubeMX
・OS windows 10 pro
・本

LCDモジュールを動かしていきたいと思います。
LCDのコントローラにルネサスのHD44780の互換品ICを搭載した
LCDキャラクタディスプレイモジュール 16×2行 バックライト付白抜き: ディスプレイ・表示器 秋月電子通商-電子部品・ネット通販
を今回は使用していきます。
よくあるE,RS,R/WとDB0~7の内のDB0~3の4bitを使用して駆動するあれです。
まずはSTM32CubeMXの設定を行います。
ピンアサインは
E: PC0
RS: PC1
DB4: PB4
DB5: PB5
DB6: PB6
DB7: PB7
としました。
f:id:CCWO:20160915005322p:plain
ソースの詳しい解説はおいておいて、lcd.hとlcd.cをApplication/Userフォルダに追加します。
(フォルダを選択して、右クリック→Add New Item to Group '~'→Type C or H file→Nameを変更→LocationをC:\WorkSpace\MDKARM\F401RE_LCD_00\Src\に変更)
・lcd.h

#ifndef _LCD_H_
#define _LCD_H_

/*===============================================================
関数名:	LcdCls
機能:		LCDの表示をクリアする
===============================================================*/
extern void LcdCls(void);

/*===============================================================
関数名:	LcdDisplayMode
機能:		LCDの表示モードを設定する
			disp: LCD全体の表示のON/OFF
			cursor: カーソル表示のON/OFF
			blink: カーソル位置の文字のブリンクのON/OFF
===============================================================*/
extern void LcdDisplayMode(char disp, char cursor, char blink);

/*===============================================================
関数名:	LcdInit
機能:		LCDの初期化. 起動時に一回だけ呼び出す.
===============================================================*/
extern void LcdInit(void);

/*===============================================================
関数名:	LcdPutc
機能:		現在設定されているLCDのDDRAMアドレスへ1文字出力する.
===============================================================*/
extern void LcdPuts(char *str);

/*===============================================================
関数名:	LcdXy
機能:		引数 x, y で示された位置へ文字列sを表示する.
===============================================================*/
extern void LcdXy(char x, char y);

#endif /*end of #ifndef _LCD_H_*/

・lcd.c

#include "lcd.h"
#include "stm32f4xx_hal.h"

#define CMD 	0
#define DAT 	1
#define ON 	1
#define OFF 	0
#define IN		1
#define OUT 	0

// LCD Control(ハードウェア依存部)
#define E_PORT		GPIOC
#define E_PIN			(1<<0)
#define RS_PORT	GPIOC
#define RS_PIN		(1<<1)

void LCD_RW(char act);
void LCD_E(char act);
void LCD_RS(char act);
void LCD_OUT(int dat);

void LCD_RW(char act)
{
	// RW = L
}

void LCD_E(char act)
{
	if(act){
		HAL_GPIO_WritePin(E_PORT, E_PIN, GPIO_PIN_SET);
	}else{
		HAL_GPIO_WritePin(E_PORT, E_PIN, GPIO_PIN_RESET);
	}
}

void LCD_RS(char act)
{
	if(act){
		HAL_GPIO_WritePin(RS_PORT, RS_PIN, GPIO_PIN_SET);
	}else{
		HAL_GPIO_WritePin(RS_PORT, RS_PIN, GPIO_PIN_RESET);
	}
}

void LCD_OUT(int dat)
{
	int pin;
	pin = dat & 0x0f0;
	HAL_GPIO_WritePin(GPIOB, pin, GPIO_PIN_SET);
	pin = (~pin) & 0x0f0;
	HAL_GPIO_WritePin(GPIOB, pin, GPIO_PIN_RESET);
}

void lcd_write8(char reg, char dat);
void lcd_write(char reg, char dat);

// 8bit mode write
void lcd_write8(char reg, char dat)
{
	LCD_RS(reg);
	LCD_OUT(dat);
	LCD_E(ON);
	HAL_Delay(1);
	LCD_E(OFF);
	HAL_Delay(2);
}

// 4bit mode write
void lcd_write(char reg, char dat)
{
	LCD_RS(reg);
	LCD_OUT(dat);
	LCD_E(ON);
	HAL_Delay(1);
	LCD_E(OFF);
	dat<<=4;
	LCD_OUT(dat);
	LCD_E(ON);
	HAL_Delay(1);
	LCD_E(OFF);
}

void LcdCls()
{
	lcd_write(CMD, 1);
}

void LcdDisplayMode(char disp, char cursor, char blink)
{
	char mode = 0x08;
	if(disp) mode |= 0x04;
	if(cursor) mode |= 0x02;
	if(blink) mode |= 0x01;
	lcd_write(CMD, mode);
}

void LcdInit()
{
	// LCDの初期化
	LCD_RW(OUT);
	HAL_Delay(30);
	lcd_write8(CMD, 0x30);		// Function 8bit
	HAL_Delay(5);
	lcd_write8(CMD, 0x30);		// Function 8bit
	HAL_Delay(5);
	lcd_write8(CMD, 0x30);		// Function 8bit
	HAL_Delay(5);
	
	lcd_write8(CMD, 0x20);		// Function 4bit
	HAL_Delay(5);
	lcd_write8(CMD, 0x20);		// Function 4bit
	HAL_Delay(5);
	lcd_write8(CMD, 0x20);		// Function 4bit
	HAL_Delay(5);
	
	LcdDisplayMode(0, 0, 0);
	HAL_Delay(5);
	LcdCls();
	HAL_Delay(5);
	lcd_write(CMD, 0x06);			// Entry Mode Set
	HAL_Delay(40);
	LcdDisplayMode(1, 1, 1);
	HAL_Delay(5);
}

void LcdPutc(char c)
{
	lcd_write(DAT, c);
}

void LcdPuts(char *str)
{
	while(*str){
		LcdPutc(*str);
		str++;
	}
}

void LcdXy(char x, char y)
{
	unsigned char adr;
	adr = (x+(y%2)*0x40) | 0x80;
	lcd_write(CMD, adr);
	HAL_Delay(10);
}

・main.c

/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx_hal.h"
#include "lcd.h"
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */
void HAL_Delay_s(int sec)
{
	while(sec){
		HAL_Delay(1000);
		sec--;
	}
}
/* USER CODE END 0 */

int main(void)
{

  /* USER CODE BEGIN 1 */

  /* 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();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();

  /* USER CODE BEGIN 2 */
	LcdInit();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  HAL_Delay_s(1);
	  LcdPuts((char *)"NUCLEO F401RE");
	  HAL_Delay_s(1);
	  LcdCls();
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

としました。
実行結果がこちら。(LcdXyにバグがあるような・・・)
f:id:CCWO:20160915101728j:plain