Created
November 23, 2021 05:07
-
-
Save ak1211/6ffd2f1b7b14edabc63c310362018dfd to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* i2c_lcd.c | |
* | |
* Created on: 2021/11/22 | |
* Author: Akihiro Yamamoto | |
* | |
* Copyright 2021 Akihiro Yamamoto | |
* Licensed under the Apache License, Version 2.0 | |
* | |
*/ | |
#include "main.h" | |
#include <stdint.h> | |
#include <string.h> | |
#include <i2c_lcd.h> | |
#if __STDC_VERSION__ >= 199901L | |
#else | |
#error ISO C99 or newer compiler required. | |
#endif | |
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) | |
#define I2C_LCD_TIMEOUT ((uint8_t)100) | |
#define I2C_LCD_ADDRESS ((uint8_t)0x3e) | |
#define I2C_LCD_CBYTE_COMMAND ((uint8_t)0x00) | |
#define I2C_LCD_CBYTE_DATA ((uint8_t)0x40) | |
#define I2C_LCD_CBYTE_CONTINUATION ((uint8_t)0x80) | |
typedef struct { | |
icon_code_t icon_code; | |
uint8_t addr; | |
uint8_t bit; | |
} icon_t; | |
// @formatter:off | |
static const icon_t I2C_LCD_ICON_DATA[13] = { | |
{ I2C_LCD_ICON_a, 0x00, 0b10000 }, // S1 ANTENNA | |
{ I2C_LCD_ICON_b, 0x02, 0b10000 }, // S11 TEL | |
{ I2C_LCD_ICON_c, 0x04, 0b10000 }, // S21 | |
{ I2C_LCD_ICON_d, 0x06, 0b10000 }, // S31 | |
{ I2C_LCD_ICON_e, 0x07, 0b10000 }, // S36 UP ARROW | |
{ I2C_LCD_ICON_f, 0x07, 0b01000 }, // S37 DOWN ARROW | |
{ I2C_LCD_ICON_g, 0x09, 0b10000 }, // S46 LOCKED | |
{ I2C_LCD_ICON_h, 0x0b, 0b10000 }, // S56 | |
{ I2C_LCD_ICON_i, 0x0d, 0b10000 }, // S66 BATTERY LOW | |
{ I2C_LCD_ICON_j, 0x0d, 0b01000 }, // S67 BATTERY MID | |
{ I2C_LCD_ICON_k, 0x0d, 0b00100 }, // S68 BATTERY HIGH | |
{ I2C_LCD_ICON_l, 0x0d, 0b00010 }, // S69 BATTERY FRAME | |
{ I2C_LCD_ICON_m, 0x0f, 0b10000 }, // S76 | |
}; | |
// @formatter:on | |
// @formatter:off | |
inline static void i2c_lcd_wait_a_moment() { | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
// 10 | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
// 20 | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
// 30 | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
// 40 | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); asm("NOP"); | |
// 50 | |
} | |
// @formatter:on | |
void i2c_lcd_init(I2C_HandleTypeDef *hi2c) { | |
uint8_t contrast = 0b101000; | |
/* first step */ | |
{ | |
// @formatter:off | |
uint8_t sequence[] = { | |
0b00111000, // function set | |
0b00111001, // function set | |
0b00010100, // interval osc | |
0b01110000 | (contrast & 0xf), // contrast Low | |
0b01011100 | ((contrast >> 4) & 0x3), // contast High/icon/power | |
0b01101100, // follower control | |
}; | |
// @formatter:on | |
i2c_lcd_send_commands(hi2c, ARRAY_SIZE(sequence), sequence); | |
} | |
HAL_Delay(200); | |
/* second step */ | |
{ | |
// @formatter:off | |
uint8_t sequence[] = { | |
0b00111000, // function set | |
0b00001100, // Display On | |
0b00000001, // Clear Display | |
}; | |
// @formatter:on | |
i2c_lcd_send_commands(hi2c, ARRAY_SIZE(sequence), sequence); | |
} | |
HAL_Delay(2); | |
} | |
static void master_transmit(I2C_HandleTypeDef *hi2c, uint8_t cbyte, size_t size, uint8_t data[size]) { | |
size_t i; | |
uint8_t buff[size * 2]; | |
for (i = 0; i < (size - 1); ++i) { | |
buff[i * 2 + 0] = I2C_LCD_CBYTE_CONTINUATION | cbyte; | |
buff[i * 2 + 1] = data[i]; | |
} | |
buff[i * 2 + 0] = cbyte; | |
buff[i * 2 + 1] = data[i]; | |
HAL_I2C_Master_Transmit(hi2c, I2C_LCD_ADDRESS << 1, buff, ARRAY_SIZE(buff), | |
I2C_LCD_TIMEOUT); | |
i2c_lcd_wait_a_moment(); | |
} | |
void i2c_lcd_send_commands(I2C_HandleTypeDef *hi2c, size_t size, | |
uint8_t cmds[size]) { | |
master_transmit(hi2c, I2C_LCD_CBYTE_COMMAND, size, cmds); | |
} | |
void i2c_lcd_send_data(I2C_HandleTypeDef *hi2c, size_t size, uint8_t data[size]) { | |
master_transmit(hi2c, I2C_LCD_CBYTE_DATA, size, data); | |
} | |
void i2c_lcd_puts(I2C_HandleTypeDef *hi2c, char *s) { | |
i2c_lcd_send_data(hi2c, strlen(s), (uint8_t*) s); | |
} | |
void i2c_lcd_show_icon(I2C_HandleTypeDef *hi2c, icon_code_t bitflag) { | |
uint8_t buff[16] = { 0 }; | |
for (uint8_t i = 0; i < ARRAY_SIZE(I2C_LCD_ICON_DATA); ++i) { | |
const icon_t *p = &I2C_LCD_ICON_DATA[i]; | |
if (bitflag & p->icon_code) { | |
buff[p->addr] |= p->bit; | |
} | |
} | |
for (uint8_t addr = 0; addr < ARRAY_SIZE(buff); ++addr) { | |
// @formatter:off | |
uint8_t cmds[] = { | |
0b00111001, // function set | |
0b01000000 | addr, // set icon address | |
}; | |
// @formatter:on | |
i2c_lcd_send_commands(hi2c, ARRAY_SIZE(cmds), cmds); | |
i2c_lcd_send_datum(hi2c, buff[addr]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment