#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stm32c0xx_hal.h>
#define LCD_ADDR (0x27 << 1) // адрес дисплея, сдвинутый на 1 бит влево (HAL работает с I2C-адресами, сдвинутыми на 1 бит влево)
#define LCD_DELAY_MS 5 // пауза перед высвечиванием символа
#define BACKLIGHT (1 << 3) // управление подсветкой
#define PIN_RS (1 << 0) // если на ножке 0, данные воспринимаются как команда, если 1 - как символы для вывода
#define PIN_EN (1 << 2) // бит, по изменению сост. которого считывается информация
// ST Nucleo Green user LED (PA5)
I2C_HandleTypeDef hi2c1;
UART_HandleTypeDef huart2;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART2_UART_Init(void);
static void MX_I2C1_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART2_UART_Init();
// void I2C_Scan ();
// MX_I2C1_Init();
I2C_send(0b00110000,0); // 8ми битный интерфейс
I2C_send(0b00000010,0); // установка курсора в начале строки
I2C_send(0b00001100,0); // нормальный режим работы
I2C_send(0b00000001,0); // очистка дисплея
/* USER CODE END 2 */
I2C_send(0b10000000,0); // переход на 1 строку, тут не обязателен
LCD_SendString(" Hello Habr");
I2C_send(0b11000000,0); // переход на 2 строку
LCD_SendString(" STM32 + LCD 1602");
I2C_send(0b10010100,0); // переход на 3 строку
LCD_SendString(" +LCD 2004A");
I2C_send(0b11010100,0); // переход на 4 строку
LCD_SendString(" library HAL");
printf("Hello, %s!\n", "Wokwi2");
char received;
while (1)
{
// I2C_Scan ();
}
return 0;
}
/**
@brief System Clock Configuration
@retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK
| RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
/**
@brief USART2 Initialization Function
@param None
@retval None
*/
static void MX_USART2_UART_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
// PA2 ------> USART2_TX
// PA3 ------> USART2_RX
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
}
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
printf("Hello, %s!\n", "Wokwi1");
hi2c1.Instance = I2C1;
hi2c1.Init.Timing = 0x20303E5D;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/** Configure Analogue filter
*/
if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
{
Error_Handler();
}
/** Configure Digital filter
*/
if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* USER CODE BEGIN MX_GPIO_Init_1 */
/* USER CODE END MX_GPIO_Init_1 */
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/* USER CODE BEGIN MX_GPIO_Init_2 */
/* USER CODE END MX_GPIO_Init_2 */
}
void Error_Handler(void)
{
/* User can add his own implementation to report the HAL error return state */
}
// The following makes printf() write to USART2:
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
int _write(int file, uint8_t *ptr, int len)
{
switch (file)
{
case STDOUT_FILENO:
HAL_UART_Transmit(&huart2, ptr, len, HAL_MAX_DELAY);
break;
case STDERR_FILENO:
HAL_UART_Transmit(&huart2, ptr, len, HAL_MAX_DELAY);
break;
default:
return -1;
}
return len;
}
void LCD_SendString(char *str)
{
// *char по сути является строкой
while(*str) { // пока строчка не закончится
I2C_send((uint8_t)(*str), 1); // передача первого символа строки
str++; // сдвиг строки налево на 1 символ
}
}
void I2C_Scan ()
{
// создание переменной, содержащей статус
HAL_StatusTypeDef res;
// сообщение о начале процедуры
char info[] = "Scanning I2C bus...\r\n";
// отправка сообщения по UART
HAL_UART_Transmit(&huart2, (uint8_t*)info, strlen(info), HAL_MAX_DELAY);
/* &huart2 - адрес используемого UART
* (uint8_t*)info - указатель на значение для отправки
* strlen(info) - длина отправляемого сообщения
* HAL_MAX_DELAY - задержка
*/
// перебор всех возможных адресов
for(uint16_t i = 0; i < 128; i++)
{
// проверяем, готово ли устройство по адресу i для связи
res = HAL_I2C_IsDeviceReady(&hi2c1, i << 1, 1, HAL_MAX_DELAY);
// если да, то
if(res == HAL_OK)
{
char msg[64];
// запись адреса i, на который откликнулись, в строку в виде
// 16тиричного значения:
snprintf(msg, sizeof(msg), "0x%02X", i);
// отправка номера откликнувшегося адреса
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY);
// переход на новую строчку
HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY);
}
else HAL_UART_Transmit(&huart2, (uint8_t*)".", 1, HAL_MAX_DELAY);
}
HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", 2, HAL_MAX_DELAY);
}
void I2C_send(uint8_t data, uint8_t flags)
{
HAL_StatusTypeDef res;
// бесконечный цикл
// for(;;) {
// // проверяем, готово ли устройство по адресу lcd_addr для связи
// res = HAL_I2C_IsDeviceReady(&hi2c1, LCD_ADDR, 1, HAL_MAX_DELAY);
// если да, то выходим из бесконечного цикла
// if(res == HAL_OK) break;
// }
// операция И с 1111 0000 приводит к обнулению бит с 0 по 3, остаются биты с 4 по 7
uint8_t up = data & 0xF0;
// то же самое, но data сдвигается на 4 бита влево
uint8_t lo = (data << 4) & 0xF0;
uint8_t data_arr[4];
// 4-7 биты содержат информацию, биты 0-3 настраивают работу дисплея
data_arr[0] = up|flags|BACKLIGHT|PIN_EN;
// дублирование сигнала, на выводе Е в этот раз 0
data_arr[1] = up|flags|BACKLIGHT;
data_arr[2] = lo|flags|BACKLIGHT|PIN_EN;
data_arr[3] = lo|flags|BACKLIGHT;
HAL_I2C_Master_Transmit(&hi2c1, LCD_ADDR, data_arr, sizeof(data_arr), HAL_MAX_DELAY);
HAL_Delay(LCD_DELAY_MS);
}