W poprzednim wpisie opisałem obliczanie liczb pierwszych i miganie diodą LINK, program ten można w prosty sposób rozszerzyć o wyświetlanie tych danych na LCD zamiast po UART.

Uwaga! LCD musi mieć konwerter sygnału wyświetlacza I2C np. układ PCF8574.

LCD1602 STM32 i2c
1. Pobiermay obrać bibliotekę do obsługi LCD po I2C
https://github.com/ptrre/kurs-stm32-e16-lcd/blob/master/Core/Src/lcd_i2c.c
https://github.com/ptrre/kurs-stm32-e16-lcd/blob/master/Core/Inc/lcd_i2c.h
Pliki należy pobrać i skopiować do Inc (plik nagłówkowy *.h) oraz Src (plik źródłowy *.c).

2. W STM32CubeIDE wchodzimy w Pinout & Configuration -> Connectivity -> I2C1 -> Mode i zmieniamy I2C na I2C.

3. Podłączamy zasilanie obojętnie z jakich pinów, oraz I2C1_SDA oraz I2C1_SCL zgodnie z pinoutem naszego STM32.

4. Piszemy kod

1
2
3
4
5
/* USER CODE BEGIN Includes */
#include "lcd_i2c.h"
#include <stdbool.h>
#include <stdio.h>
/* USER CODE END Includes */
1
2
3
4
/* USER CODE BEGIN PV */
[...]
struct lcd_disp disp;
/* USER CODE END Variables */
1
2
3
4
5
6
7
8
 /* USER CODE BEGIN 2 */
        disp.addr = (0x27 << 1);
        disp.bl = true;
        lcd_init(&disp);
        sprintf((char *)disp.f_line, "");
        sprintf((char *)disp.s_line, "");
        lcd_display(&disp);
  /* USER CODE END 2 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* USER CODE END Header_StartTask02 */
void StartTask02(void *argument)
{
  /* USER CODE BEGIN StartTask02 */
  /* Infinite loop */
  for(;;)
  {
          for(uint32_t i=0;; i++){
                    int divide = 0;
                    for(uint32_t j=1; j < i+1; j++){
                        if((i % j) == 0) divide++;
                        if(divide > 2) break;
                    }
                    if(divide == 2){
                            printfx("%d\r\n", i);
                            sprintf((char *)disp.f_line, "%i", i); //string ktory bedzie wyslany
                            lcd_display(&disp); //przeslanie danych
                            osDelay(1);
                    }
          }
  }
  /* USER CODE END StartTask02 */
}

5. W bibliotece można funkcji init dodać dodatkowy parametr zamiast używać define z i2c, w całości ta biblioteka wyglądałaby dla Bluepill i i2c1 tak:
lcd1602_i2c.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/* The MIT License
 *
 * Copyright (c) 2020 Piotr Duba
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#ifndef INC_LCD_I2C_H_
#define INC_LCD_I2C_H_

#include <stdbool.h>
#include <stdint.h>

/*
 *         PCF8574 <-> HD44780
 *
 * I2C I/O   P7 P6 P5 P4 P3 P2 P1 P0
 * LCD       D7 D6 D5 D4 BL EN RW RS
 *
 * */


// #define HI2C_DEF hi2c1
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_i2c.h"

#define RS_PIN 0x01
#define RW_PIN 0x02
#define EN_PIN 0x04
#define BL_PIN 0x08

#define INIT_8_BIT_MODE 0x30
#define INIT_4_BIT_MODE 0x02

#define CLEAR_LCD       0x01

#define UNDERLINE_OFF_BLINK_OFF         0x0C
#define UNDERLINE_OFF_BLINK_ON          0x0D
#define UNDERLINE_ON_BLINK_OFF          0x0E
#define UNDERLINE_ON_BLINK_ON           0x0F

#define FIRST_CHAR_LINE_1       0x80
#define FIRST_CHAR_LINE_2       0xC0

struct lcd_disp {
        uint8_t addr;
        char f_line[17];
        char s_line[17];
        bool bl;
};

I2C_HandleTypeDef *hi2c;
void lcd_init(struct lcd_disp * lcd, I2C_HandleTypeDef *);
void lcd_write(uint8_t addr, uint8_t data, uint8_t xpin);
void lcd_display(struct lcd_disp * lcd);
void lcd_clear(struct lcd_disp * lcd);

#endif /* INC_LCD_I2C_H_ */

lcd1602_i2c.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* The MIT License
 *
 * Copyright (c) 2020 Piotr Duba
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */


#include "lcd1602_i2c.h"
#include "stm32f1xx_hal.h"
#include "stm32f1xx_hal_i2c.h"



void lcd_init(struct lcd_disp * lcd, I2C_HandleTypeDef *_hi2c1)
{
        hi2c = _hi2c1;
        uint8_t xpin = 0;
        /* set backlight */
        if(lcd->bl)
        {
                xpin = BL_PIN;
        }

        /* init sequence */
        HAL_Delay(40);
        lcd_write(lcd->addr, INIT_8_BIT_MODE, xpin);
        HAL_Delay(5);
        lcd_write(lcd->addr, INIT_8_BIT_MODE, xpin);
        HAL_Delay(1);
        lcd_write(lcd->addr, INIT_8_BIT_MODE, xpin);

        /* set 4-bit mode */
        lcd_write(lcd->addr, INIT_4_BIT_MODE, xpin);

        /* set cursor mode */
        lcd_write(lcd->addr, UNDERLINE_OFF_BLINK_OFF, xpin);

        /* clear */
        lcd_clear(lcd);

}

void lcd_write(uint8_t addr, uint8_t data, uint8_t xpin)
{
        uint8_t tx_data[4];

        /* split data */
        tx_data[0] = (data & 0xF0) | EN_PIN | xpin;
        tx_data[1] = (data & 0xF0) | xpin;
        tx_data[2] = (data << 4) | EN_PIN | xpin;
        tx_data[3] = (data << 4) | xpin;

        /* send data via i2c */
        HAL_I2C_Master_Transmit(hi2c, addr, tx_data, 4, 100);

        HAL_Delay(5);
}

void lcd_display(struct lcd_disp * lcd)
{
        uint8_t xpin = 0, i = 0;

        /* set backlight */
        if(lcd->bl)
        {
                xpin = BL_PIN;
        }

        lcd_clear(lcd);

        /* send first line data */
        lcd_write(lcd->addr, FIRST_CHAR_LINE_1, xpin);
        while(lcd->f_line[i])
        {
                lcd_write(lcd->addr, lcd->f_line[i], (xpin | RS_PIN));
                i++;
        }

        /* send second line data */
        i = 0;
        lcd_write(lcd->addr, FIRST_CHAR_LINE_2, xpin);
        while(lcd->s_line[i])
        {
                lcd_write(lcd->addr, lcd->s_line[i], (xpin | RS_PIN));
                i++;
        }
}

void lcd_clear(struct lcd_disp * lcd)
{
        uint8_t xpin = 0;

        /* set backlight */
        if(lcd->bl)
        {
                xpin = BL_PIN;
        }

        /* clear display */
        lcd_write(lcd->addr, CLEAR_LCD, xpin);
}
C, STM32