728x90

728x90

Sunday, November 16, 2025

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example

In previous post I use the HSPI1 communication interface of the STM32F103C8T6 to interface with the SN74HC595N serial-in-parallel out shift registers to control LEDs and 7-Segment display. In this programming example I use this chip to control the HD44780 compatible LCD controller. I use the TC1604A-01(R) LCM module from Tinsharp that I keep it many years now.

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example

The SPI communication is one direction that the master micro-controller just send serial data including command and display data to the LCD module. Hence the LCD R/W pin must wired to GND. 

SN74HC595 chips in DIP package

 

The controlling mode is 4-bit data mode that need to send the 8-bit command/data twice via its high nibble and low nibble.

The MCU clock is 64MHz that is driven from its 8MHz HSI and PLL.

STM32 Blue Pill HSPI1 and SN74HC595N LED Example
Clock Configuration

The operate in half duplex master mode with a baud rate of 16Mbits per second.

STM32 Blue Pill HSPI1 and SN74HC595N LED Example
SPI and GPIO Setting

The NSS pin is ignored. So the enable pin must be set via software. I select PB4 as the SPI slave select pin. The Display Data RAM (DD RAM) of the TC1604A-01(R) is shown in the figure below.

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example
I put the LCD driver with the main.c source code.

  1. /* USER CODE BEGIN Header */
  2. /**
  3. ******************************************************************************
  4. * @file : main.c
  5. * @brief : Main program body
  6. ******************************************************************************
  7. * @attention
  8. *
  9. * <h2><center>&copy; Copyright (c) 2025 STMicroelectronics.
  10. * All rights reserved.</center></h2>
  11. *
  12. * This software component is licensed by ST under BSD 3-Clause license,
  13. * the "License"; You may not use this file except in compliance with the
  14. * License. You may obtain a copy of the License at:
  15. * opensource.org/licenses/BSD-3-Clause
  16. *
  17. ******************************************************************************
  18. */
  19. /* USER CODE END Header */
  20. /* Includes ------------------------------------------------------------------*/
  21. #include "main.h"

  22. /* Private includes ----------------------------------------------------------*/
  23. /* USER CODE BEGIN Includes */

  24. /* USER CODE END Includes */

  25. /* Private typedef -----------------------------------------------------------*/
  26. /* USER CODE BEGIN PTD */

  27. /* USER CODE END PTD */

  28. /* Private define ------------------------------------------------------------*/
  29. /* USER CODE BEGIN PD */
  30. /* USER CODE END PD */

  31. /* Private macro -------------------------------------------------------------*/
  32. /* USER CODE BEGIN PM */

  33. /* USER CODE END PM */

  34. /* Private variables ---------------------------------------------------------*/
  35. SPI_HandleTypeDef hspi1;

  36. /* USER CODE BEGIN PV */

  37. /* USER CODE END PV */

  38. /* Private function prototypes -----------------------------------------------*/
  39. void SystemClock_Config(void);
  40. static void MX_GPIO_Init(void);
  41. static void MX_SPI1_Init(void);
  42. /* USER CODE BEGIN PFP */

  43. /* USER CODE END PFP */

  44. /* Private user code ---------------------------------------------------------*/
  45. /* USER CODE BEGIN 0 */

  46. /* USER CODE END 0 */

  47. uint8_t DPORT;

  48. void delay1(uint16_t dTime){
  49. for(uint16_t i=0;i<dTime;i++);
  50. }

  51. void delay2(uint8_t dTime){
  52. for(uint8_t i=0;i<dTime;i++) delay1(5000);
  53. }

  54. void en(void){
  55. HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET);
  56. delay1(1000);
  57. HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET);
  58. }

  59. void lcdCmd(uint8_t cmd){
  60. uint8_t temp=0x08;
  61. DPORT=temp|(cmd&0xF0);
  62. HAL_SPI_Transmit(&hspi1,&DPORT,1,10);
  63. en();
  64. delay1(10);
  65. temp=0;
  66. DPORT=temp|(cmd&0xF0);
  67. HAL_SPI_Transmit(&hspi1,&DPORT,1,10);
  68. en();
  69. delay1(100);

  70. temp=0x08;
  71. DPORT=temp|(cmd<<4);
  72. HAL_SPI_Transmit(&hspi1,&DPORT,1,10);
  73. en();
  74. delay1(10);
  75. temp=0;
  76. DPORT=temp|(cmd<<4);
  77. HAL_SPI_Transmit(&hspi1,&DPORT,1,10);
  78. en();
  79. }

  80. void lcdDat(uint8_t dat){
  81. uint8_t temp=0x0A;
  82. DPORT=temp|(dat&0xF0);
  83. HAL_SPI_Transmit(&hspi1,&DPORT,1,10);
  84. en();
  85. delay1(10);
  86. temp=0x02;
  87. DPORT=temp|(dat&0xF0);
  88. HAL_SPI_Transmit(&hspi1,&DPORT,1,10);
  89. en();
  90. delay1(100);

  91. temp=0x0A;
  92. DPORT=temp|(dat<<4);
  93. HAL_SPI_Transmit(&hspi1,&DPORT,1,10);
  94. en();
  95. delay1(10);
  96. temp=0x02;
  97. DPORT=temp|(dat<<4);
  98. HAL_SPI_Transmit(&hspi1,&DPORT,1,10);
  99. en();
  100. }

  101. void lcdInit(void){
  102. DPORT=0x00;
  103. delay1(2000);
  104. lcdCmd(0x33);
  105. delay1(100);
  106. lcdCmd(0x32);
  107. delay1(100);
  108. lcdCmd(0x28);
  109. delay1(100);
  110. lcdCmd(0x0F);
  111. delay1(100);
  112. lcdCmd(0x01);
  113. delay1(2000);
  114. lcdCmd(0x06);
  115. delay1(100);
  116. }

  117. void lcdStr(uint8_t *str){
  118. while(*str) lcdDat(*str++);
  119. }

  120. void lcdXY(uint8_t x,uint8_t y){
  121. // 20x4 LCD
  122. //uint8_t tbe[]={0x80,0xC0,0x94,0xD4};
  123. // 16x4 LCD
  124. uint8_t tbe[]={0x80,0xC0,0x90,0xD0};
  125. lcdCmd(tbe[y-1]+x-1);
  126. delay1(100);
  127. }

  128. void lcdClear(void){
  129. lcdCmd(0x01);
  130. delay1(12000);
  131. }

  132. /**
  133. * @brief The application entry point.
  134. * @retval int
  135. */
  136. int main(void)
  137. {
  138. /* USER CODE BEGIN 1 */

  139. /* USER CODE END 1 */

  140. /* MCU Configuration--------------------------------------------------------*/

  141. /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  142. HAL_Init();

  143. /* USER CODE BEGIN Init */

  144. /* USER CODE END Init */

  145. /* Configure the system clock */
  146. SystemClock_Config();

  147. /* USER CODE BEGIN SysInit */

  148. /* USER CODE END SysInit */

  149. /* Initialize all configured peripherals */
  150. MX_GPIO_Init();
  151. MX_SPI1_Init();
  152. /* USER CODE BEGIN 2 */
  153. HAL_Delay(100);
  154. lcdInit();
  155. lcdClear();
  156. lcdCmd(0x0C);
  157. lcdXY(3,1);
  158. lcdStr("Hello World!");

  159. lcdXY(3,2);
  160. lcdStr("STM32F103C8T6 ");

  161. lcdXY(1,3);
  162. lcdStr("HSPI1 SN74HC595N");

  163. lcdXY(1,4);
  164. lcdStr("TC1604A-01R LCD");

  165. HAL_Delay(5000);
  166. lcdClear();

  167. lcdXY(1,1);
  168. lcdStr("STM32CubeIDE");

  169. lcdXY(1,2);
  170. lcdStr("version 1.6.0");

  171. lcdXY(1,3);
  172. lcdStr("HAL Library...");

  173. lcdXY(1,4);
  174. lcdStr("16/11/2025");

  175. /* USER CODE END 2 */

  176. /* Infinite loop */
  177. /* USER CODE BEGIN WHILE */
  178. while (1)
  179. {
  180. /* USER CODE END WHILE */

  181. /* USER CODE BEGIN 3 */
  182. }
  183. /* USER CODE END 3 */
  184. }

  185. /**
  186. * @brief System Clock Configuration
  187. * @retval None
  188. */
  189. void SystemClock_Config(void)
  190. {
  191. RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  192. RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  193. /** Initializes the RCC Oscillators according to the specified parameters
  194. * in the RCC_OscInitTypeDef structure.
  195. */
  196. RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  197. RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  198. RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  199. RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  200. RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;
  201. RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;
  202. if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  203. {
  204. Error_Handler();
  205. }
  206. /** Initializes the CPU, AHB and APB buses clocks
  207. */
  208. RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
  209. |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  210. RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  211. RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  212. RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  213. RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  214. if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  215. {
  216. Error_Handler();
  217. }
  218. }

  219. /**
  220. * @brief SPI1 Initialization Function
  221. * @param None
  222. * @retval None
  223. */
  224. static void MX_SPI1_Init(void)
  225. {

  226. /* USER CODE BEGIN SPI1_Init 0 */

  227. /* USER CODE END SPI1_Init 0 */

  228. /* USER CODE BEGIN SPI1_Init 1 */

  229. /* USER CODE END SPI1_Init 1 */
  230. /* SPI1 parameter configuration*/
  231. hspi1.Instance = SPI1;
  232. hspi1.Init.Mode = SPI_MODE_MASTER;
  233. hspi1.Init.Direction = SPI_DIRECTION_1LINE;
  234. hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
  235. hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  236. hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  237. hspi1.Init.NSS = SPI_NSS_SOFT;
  238. hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
  239. hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  240. hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  241. hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  242. hspi1.Init.CRCPolynomial = 10;
  243. if (HAL_SPI_Init(&hspi1) != HAL_OK)
  244. {
  245. Error_Handler();
  246. }
  247. /* USER CODE BEGIN SPI1_Init 2 */

  248. /* USER CODE END SPI1_Init 2 */

  249. }

  250. /**
  251. * @brief GPIO Initialization Function
  252. * @param None
  253. * @retval None
  254. */
  255. static void MX_GPIO_Init(void)
  256. {
  257. GPIO_InitTypeDef GPIO_InitStruct = {0};

  258. /* GPIO Ports Clock Enable */
  259. __HAL_RCC_GPIOA_CLK_ENABLE();

  260. /*Configure GPIO pin Output Level */
  261. HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);

  262. /*Configure GPIO pin : PA4 */
  263. GPIO_InitStruct.Pin = GPIO_PIN_4;
  264. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  265. GPIO_InitStruct.Pull = GPIO_NOPULL;
  266. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  267. HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  268. }

  269. /* USER CODE BEGIN 4 */

  270. /* USER CODE END 4 */

  271. /**
  272. * @brief This function is executed in case of error occurrence.
  273. * @retval None
  274. */
  275. void Error_Handler(void)
  276. {
  277. /* USER CODE BEGIN Error_Handler_Debug */
  278. /* User can add his own implementation to report the HAL error return state */
  279. __disable_irq();
  280. while (1)
  281. {
  282. }
  283. /* USER CODE END Error_Handler_Debug */
  284. }

  285. #ifdef USE_FULL_ASSERT
  286. /**
  287. * @brief Reports the name of the source file and the source line number
  288. * where the assert_param error has occurred.
  289. * @param file: pointer to the source file name
  290. * @param line: assert_param error line source number
  291. * @retval None
  292. */
  293. void assert_failed(uint8_t *file, uint32_t line)
  294. {
  295. /* USER CODE BEGIN 6 */
  296. /* User can add his own implementation to report the file name and line number,
  297. ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  298. /* USER CODE END 6 */
  299. }
  300. #endif /* USE_FULL_ASSERT */

  301. /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/


I made my own DIY SN74HC595N LCD driver controlling a TC1604A-01(R) LCM module.

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example

It can be used with some Arduino libraries. It is very easy to use as it needs only five pins.

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example
Simulation #1

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example
Simulation #2

I use Proteus VSM to simulate this example.

In real hardware this LCD module work at +5VDC only while the STM32 Blue pill input output logic voltage is +3.3VDC. However some newer LCD module with the HD44780 compatible LCD controller able to operate at +3.3VDC.

 

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example
Running Program #2

STM32 Blue Pill HSPI1 and SN74HC595N 16x4 LCD Example
Running Program #1

Click here to download this example. 


 


No comments:

Post a Comment

320x50

Search This Blog

tyro-728x90