IOC_T03: lcd_user.c

File lcd_user.c, 6.9 KB (added by franck, 4 years ago)

Affichage d'un message sur le LCD en mode user

Line 
1/*******************************************************************************
2 * lcdr_user.c - Controleur pour LCd HD44780 ( 20x4 )
3 ******************************************************************************/
4
5#include <stdio.h>
6#include <stdlib.h>
7#include <unistd.h>
8#include <stdint.h>
9#include <string.h>
10#include <sys/types.h>
11#include <sys/stat.h>
12#include <fcntl.h>
13#include <sys/mman.h>
14
15/*******************************************************************************
16 * GPIO Pins
17 ******************************************************************************/
18#define RS 7
19#define E  27
20#define D4 22
21#define D5 23
22#define D6 24
23#define D7 25
24
25#define GPIO_INPUT  0
26#define GPIO_OUTPUT 1
27
28#define RPI_BLOCK_SIZE  0xB4
29#define RPI_GPIO_BASE   0x20200000
30
31// Q1: A quoi sert le mot clé volatile
32struct gpio_s {
33    uint32_t gpfsel[7];
34    uint32_t gpset[3];
35    uint32_t gpclr[3];
36    uint32_t gplev[3];
37    uint32_t gpeds[3];
38    uint32_t gpren[3];
39    uint32_t gpfen[3];
40    uint32_t gphen[3];
41    uint32_t gplen[3];
42    uint32_t gparen[3];
43    uint32_t gpafen[3];
44    uint32_t gppud[1];
45    uint32_t gppudclk[3];
46    uint32_t test[1];
47};
48volatile struct gpio_s *gpio_regs;
49
50/*******************************************************************************
51 * GPIO Operations
52 ******************************************************************************/
53
54// Q2: Expliquer la présence des drapeaux dans open() et mmap().
55int gpio_setup(void)
56{
57
58    int mmap_fd = open("/dev/mem", O_RDWR | O_SYNC);
59    if (mmap_fd < 0) {
60        return -1;
61    }
62    gpio_regs = mmap(NULL, RPI_BLOCK_SIZE,
63                     PROT_READ | PROT_WRITE, MAP_SHARED,
64                     mmap_fd,
65                     RPI_GPIO_BASE);
66    if (gpio_regs == MAP_FAILED) {
67        close(mmap_fd);
68        return -1;
69    }
70    return 0;
71}
72
73// Q3: pourquoi appeler munmap() ?
74void gpio_teardown(void)
75{
76    munmap((void *) gpio_regs, RPI_BLOCK_SIZE);
77}
78
79void gpio_config(int gpio, int value)
80{
81    int regnum = gpio / 10;
82    int offset = (gpio % 10) * 3;
83    gpio_regs->gpfsel[regnum] &= ~(0x7 << offset);
84    gpio_regs->gpfsel[regnum] |= ((value & 0x7) << offset);
85}
86
87void gpio_write(int gpio, int value)
88{
89    int regnum = gpio / 32;
90    int offset = gpio % 32;
91    if (value&1)
92        gpio_regs->gpset[regnum] = (0x1 << offset);
93    else
94        gpio_regs->gpclr[regnum] = (0x1 << offset);
95}
96
97/*******************************************************************************
98 * LCD's Instructions ( source = doc )
99 * Ces constantes sont utilisées pour former les mots de commandes
100 * par exemple dans la fonction lcd_init()
101 ******************************************************************************/
102
103/* commands */
104#define LCD_CLEARDISPLAY        0b00000001
105#define LCD_RETURNHOME          0b00000010
106#define LCD_ENTRYMODESET        0b00000100
107#define LCD_DISPLAYCONTROL      0b00001000
108#define LCD_CURSORSHIFT         0b00010000
109#define LCD_FUNCTIONSET         0b00100000
110#define LCD_SETCGRAMADDR        0b01000000
111#define LCD_SETDDRAMADDR        0b10000000
112
113/* flags for display entry mode : combine with LCD_ENTRYMODESET */
114#define LCD_EM_RIGHT            0b00000000
115#define LCD_EM_LEFT             0b00000010
116#define LCD_EM_DISPLAYSHIFT     0b00000001
117#define LCD_EM_DISPLAYNOSHIFT   0b00000000
118
119/* flags for display on/off control : combine with LCD_DISPLAYCONTROL */
120#define LCD_DC_DISPLAYON        0b00000100
121#define LCD_DC_DISPLAYOFF       0b00000000
122#define LCD_DC_CURSORON         0b00000010
123#define LCD_DC_CURSOROFF        0b00000000
124#define LCD_DC_BLINKON          0b00000001
125#define LCD_DC_BLINKOFF         0b00000000
126
127/* flags for display/cursor shift : combine with LCD_CURSORSHIFT */
128#define LCD_CS_DISPLAYMOVE      0b00001000
129#define LCD_CS_CURSORMOVE       0b00000000
130#define LCD_CS_MOVERIGHT        0b00000100
131#define LCD_CS_MOVELEFT         0b00000000
132
133/* flags for function set : combine with LCD_FUNCTIONSET */
134#define LCD_FS_8BITMODE         0b00010000
135#define LCD_FS_4BITMODE         0b00000000
136#define LCD_FS_2LINE            0b00001000
137#define LCD_FS_1LINE            0b00000000
138#define LCD_FS_5x10DOTS         0b00000100
139#define LCD_FS_5x8DOTS          0b00000000
140
141/*******************************************************************************
142 * LCD's Operations
143 ******************************************************************************/
144
145/* generate E signal */
146void lcd_strobe(void)
147{
148    gpio_write(E, 1);
149    usleep(1);
150    gpio_write(E, 0);
151}
152
153/* send 4bits to LCD : valable pour les commande et les data */
154
155void lcd_write4bits(int data)
156{
157    /* first 4 bits */
158    gpio_write(D7, data>>7);
159    gpio_write(D6, data>>6);
160    gpio_write(D5, data>>5);
161    gpio_write(D4, data>>4);
162    lcd_strobe();
163
164    /* second 4 bits */
165    gpio_write(D7, data>>3);
166    gpio_write(D6, data>>2);
167    gpio_write(D5, data>>1);
168    gpio_write(D4, data>>0);
169    lcd_strobe();
170}
171
172void lcd_command(int cmd)
173{
174    gpio_write(RS, 0);
175    lcd_write4bits(cmd);
176    usleep(2000);               // certaines commandes sont lentes
177}
178
179void lcd_data(int character)
180{
181    gpio_write(RS, 1);
182    lcd_write4bits(character);
183    usleep(1);
184}
185
186/* initialization : pour comprendre la séquence, il faut regarder le cours */
187// Q4: Expliquer le rôle des masques : LCD_FUNCTIONSET, LCD_FS_4BITMODE, etc.
188void lcd_init(void)
189{
190    gpio_write(E, 0);
191    lcd_command(0b00110011);    /* initialization */
192    lcd_command(0b00110010);    /* initialization */
193    lcd_command(LCD_FUNCTIONSET | LCD_FS_4BITMODE | LCD_FS_2LINE | LCD_FS_5x8DOTS);
194    lcd_command(LCD_DISPLAYCONTROL | LCD_DC_DISPLAYON | LCD_DC_CURSOROFF);
195    lcd_command(LCD_ENTRYMODESET | LCD_EM_RIGHT | LCD_EM_DISPLAYNOSHIFT);
196}
197
198void lcd_clear(void)
199{
200    lcd_command(LCD_CLEARDISPLAY);
201    lcd_command(LCD_RETURNHOME);
202}
203
204// Q5: Expliquez comment fonctionne cette fonction
205void lcd_message(const char *txt)
206{
207    int a[] = { 0, 0x40, 0x14, 0x54 };
208    int len = 20;
209    int i, l;
210
211    for (i = 0, l = 0; (l < 4) && (i < strlen(txt)); l++) {
212        lcd_command(LCD_SETDDRAMADDR + a[l]);
213        for (; (i < (l + 1) * len) && (i < strlen(txt)); i++) {
214            lcd_data(txt[i]);
215        }
216    }
217}
218
219/*******************************************************************************
220 * main : affichage d'un message
221 ******************************************************************************/
222int main(int argc, char **argv)
223{
224    /* arg */
225    if (argc < 2) {
226        fprintf(stderr, "ERROR: must take a string as argument\n");
227        exit(1);
228    }
229
230    /* Retreive the mapped GPIO memory */
231    if (gpio_setup() == -1) {
232        perror("ERROR: gpio_setup\n");
233        exit(1);
234    }
235
236    /* Setting up GPIOs to output */
237    gpio_config(RS, GPIO_OUTPUT);
238    gpio_config(E,  GPIO_OUTPUT);
239    gpio_config(D4, GPIO_OUTPUT);
240    gpio_config(D5, GPIO_OUTPUT);
241    gpio_config(D6, GPIO_OUTPUT);
242    gpio_config(D7, GPIO_OUTPUT);
243
244    /* initialization */
245    lcd_init();
246    lcd_clear();
247
248    /* affichage */
249    lcd_message(argv[1]);
250
251    /* Release the GPIO memory mapping */
252    gpio_teardown();
253
254    return 0;
255}