Peri19_T03: lcd_user.c

File lcd_user.c, 6.8 KB (added by franck, 5 years ago)
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)
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 ******************************************************************************/
100
101#define BIT(b,n)   (((n)>>(b))&1)
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 */
154void lcd_write4bits(int data)
155{
156    /* first 4 bits */
157    gpio_write(D7, BIT(7, data));
158    gpio_write(D6, BIT(6, data));
159    gpio_write(D5, BIT(5, data));
160    gpio_write(D4, BIT(4, data));
161    lcd_strobe();
162
163    /* second 4 bits */
164    gpio_write(D7, BIT(3, data));
165    gpio_write(D6, BIT(2, data));
166    gpio_write(D5, BIT(1, data));
167    gpio_write(D4, BIT(0, data));
168    lcd_strobe();
169}
170
171void lcd_command(int cmd)
172{
173    gpio_write(RS, 0);
174    lcd_write4bits(cmd);
175    usleep(2000);               // certaines commandes sont lentes
176}
177
178void lcd_data(int character)
179{
180    gpio_write(RS, 1);
181    lcd_write4bits(character);
182    usleep(37);
183}
184
185/* initialization */
186// Q4: Expliquer le rôle des masques : LCD_FUNCTIONSET, LCD_FS_4BITMODE, etc.
187void lcd_init(void)
188{
189    gpio_write(E, 0);
190    lcd_command(0b00110011);    /* initialization */
191    lcd_command(0b00110010);    /* initialization */
192    lcd_command(LCD_FUNCTIONSET | LCD_FS_4BITMODE | LCD_FS_2LINE | LCD_FS_5x8DOTS);
193    lcd_command(LCD_DISPLAYCONTROL | LCD_DC_DISPLAYON | LCD_DC_CURSOROFF);
194    lcd_command(LCD_ENTRYMODESET | LCD_EM_RIGHT | LCD_EM_DISPLAYNOSHIFT);
195}
196
197void lcd_clear(void)
198{
199    lcd_command(LCD_CLEARDISPLAY);
200    lcd_command(LCD_RETURNHOME);
201}
202
203// Q5: Expliquez comment fonctionne cette fonction
204void lcd_message(const char *txt)
205{
206    int a[] = { 0, 0x40, 0x14, 0x54 };
207    int len = 20;
208    int i, l;
209
210    for (i = 0, l = 0; (l < 4) && (i < strlen(txt)); l++) {
211        lcd_command(LCD_SETDDRAMADDR + a[l]);
212        for (; (i < (l + 1) * len) && (i < strlen(txt)); i++) {
213            lcd_data(txt[i]);
214        }
215    }
216}
217
218/*******************************************************************************
219 * Finally, the main function
220 ******************************************************************************/
221int main(int argc, char **argv)
222{
223    /* arg */
224    if (argc < 2) {
225        fprintf(stderr, "ERROR: must take a string as argument\n");
226        exit(1);
227    }
228
229    /* Retreive the mapped GPIO memory */
230    if (gpio_setup() == -1) {
231        perror("ERROR: gpio_setup\n");
232        exit(1);
233    }
234
235    /* Setting up GPIOs to output */
236    gpio_config(RS, GPIO_OUTPUT);
237    gpio_config(E,  GPIO_OUTPUT);
238    gpio_config(D4, GPIO_OUTPUT);
239    gpio_config(D5, GPIO_OUTPUT);
240    gpio_config(D6, GPIO_OUTPUT);
241    gpio_config(D7, GPIO_OUTPUT);
242
243    /* initialization */
244    lcd_init();
245    lcd_clear();
246
247    /* affichage */
248    lcd_message(argv[1]);
249
250    /* Release the GPIO memory mapping */
251    gpio_teardown();
252
253    return 0;
254}