avant-propos
Dans le chapitre précédent, j'ai appris la communication série et les minuteries. Dans ce chapitre, la communication I2C sera introduite et le module OLED sera allumé à l'aide de la communication I2C. Étant donné que le module OLED prend en charge plusieurs méthodes de communication, le processus de communication I2C du module OLED utilise principalement un conditionnement secondaire sur la couche de données pour atteindre l'objectif de classer les paquets de données afin de s'adapter aux diverses méthodes de communication de l'OLED.
outil de préparation
Logiciel : STM32CubeMx, Keil5 MDK
Matériel : carte mère STM32F103C8T6, téléchargeur ST_LINK, écran à 4 broches de communication OLEDI2C
Le projet de ce chapitre a été téléchargé sur Baidu Netdisk, et ce lien est valide en permanence
Lien : https://pan.baidu.com/s/13UiC3hnn84yIsA5N1nrmmg?pwd=w8cx
Code d'extraction : w8cx
Communication I2C
I2C est un bus série synchrone à deux fils semi-duplex développé par PHILIPS. Le système à deux fils signifie que I2C n'a besoin que de deux lignes de signal, une ligne de données SDA et l'autre est la ligne d'horloge SCL. Le bus I2C permet de monter plusieurs appareils maîtres, mais l'horloge du bus ne peut être générée que par un appareil maître à la fois, et chaque appareil connecté au bus doit avoir une adresse I2C unique, et l'appareil esclave peut être adressé par l'appareil maître. La communication I2C a plusieurs classes de signaux :
Signal de démarrage S : Lorsque SCL est au niveau haut, SDA est tiré du niveau haut au niveau bas, ce qui représente le début de la transmission de données.
Signal de fin P : Lorsque SCL est au niveau haut, SDA est tiré haut du niveau bas au niveau haut, ce qui représente la fin de la transmission de données.
Signal de données : le signal de données transmet 8 bits de données à chaque fois, et chaque bit de données est transmis dans un cycle d'horloge. Lorsque SCL est au niveau haut, le niveau de la ligne de données SDA doit être stable. Lorsque SCL est au niveau bas niveau, A ce moment, le niveau sur la ligne de données SDA est autorisé à changer.
Signal de réponse ACK/NACK : Le signal de réponse est que le maître envoie des données 8 bits et que l'esclave envoie un niveau bas au maître, indiquant que les données ont été acceptées.
Le processus de transmission I2C commun pour la lecture des données du capteur est indiqué dans le tableau ci-dessous :
L'ensemble du processus de communication I2C est compris comme le processus d'envoi et de réception de la livraison express. L'adresse I2C de l'appareil est comprise comme l'adresse de l'armoire express de l'école. Les chiffres de lecture et d'écriture représentent l'envoi et la signature pour la livraison express. Signé pour le courrier . L'ensemble du processus revient à se rendre au cabinet de messagerie de l'école (adresse I2C esclave), à envoyer ou à signer pour le courrier (données) pour le numéro de cabinet (adresse du registre).
Configuration de l'IIC dans le CubeMx
1. Trouvez I2C1 sous connectivité ;
2. Configurez en tant qu'I2C ;
3. Configurez en mode rapide ;
4. Les autres restent par défaut.
Générez du code et ouvrez le projet.
Ajoutez le code suivant au projet
/**
* @brief 写数据或者指令到OLED, 如果使用的是SPI,请重写这个函数
* @param[in] dat: 要写入的字节
* @param[in] cmd: OLED_CMD 代表写入的字节是指令; OLED_DATA 代表写入的字节是数据
* @retval none
*/
void oled_write_byte(uint8_t dat, uint8_t cmd)
{
static uint8_t cmd_data[2];
if(cmd == OLED_CMD)
{
cmd_data[0] = 0x00;
}
else
{
cmd_data[0] = 0x40;
}
cmd_data[1] = dat;
HAL_I2C_Master_Transmit(&hi2c1, OLED_I2C_ADDRESS, cmd_data, 2, 10);
}
Selon la méthode de communication d'OLED, il est nécessaire d'indiquer le type de données dans le premier octet, s'il s'agit d'une commande de contrôle, il doit envoyer 0x00, et s'il s'agit d'une commande de données, il doit envoyer 0x40.
/**
* @brief 初始化OLED模块,
* @param[in] none
* @retval none
*/
void OLED_init(void)
{
oled_write_byte(0xAE, OLED_CMD); //display off
oled_write_byte(0x20, OLED_CMD); //Set Memory Addressing Mode
oled_write_byte(0x10, OLED_CMD); //00,Horizontal Addressing Mode;01,Vertical Addressing Mode;10,Page Addressing Mode (RESET);11,Invalid
oled_write_byte(0xb0, OLED_CMD); //Set Page Start Address for Page Addressing Mode,0-7
oled_write_byte(0xc8, OLED_CMD); //Set COM Output Scan Direction
oled_write_byte(0x00, OLED_CMD); //---set low column address
oled_write_byte(0x10, OLED_CMD); //---set high column address
oled_write_byte(0x40, OLED_CMD); //--set start line address
oled_write_byte(0x81, OLED_CMD); //--set contrast control register
oled_write_byte(0xff, OLED_CMD); //brightness 0x00~0xff
oled_write_byte(0xa1, OLED_CMD); //--set segment re-map 0 to 127
oled_write_byte(0xa6, OLED_CMD); //--set normal display
oled_write_byte(0xa8, OLED_CMD); //--set multiplex ratio(1 to 64)
oled_write_byte(0x3F, OLED_CMD); //
oled_write_byte(0xa4, OLED_CMD); //0xa4,Output follows RAM content;0xa5,Output ignores RAM content
oled_write_byte(0xd3, OLED_CMD); //-set display offset
oled_write_byte(0x00, OLED_CMD); //-not offset
oled_write_byte(0xd5, OLED_CMD); //--set display clock divide ratio/oscillator frequency
oled_write_byte(0xf0, OLED_CMD); //--set divide ratio
oled_write_byte(0xd9, OLED_CMD); //--set pre-charge period
oled_write_byte(0x22, OLED_CMD); //
oled_write_byte(0xda, OLED_CMD); //--set com pins hardware configuration
oled_write_byte(0x12, OLED_CMD);
oled_write_byte(0xdb, OLED_CMD); //--set vcomh
oled_write_byte(0x20, OLED_CMD); //0x20,0.77xVcc
oled_write_byte(0x8d, OLED_CMD); //--set DC-DC enable
oled_write_byte(0x14, OLED_CMD); //
oled_write_byte(0xaf, OLED_CMD); //--turn on oled panel
}
La fonction OLED_init, qui configure principalement les paramètres OLED, transmet OLED_CMD en appelant oled_write_byte et transmet les commandes de contrôle pour terminer la configuration.
/**
* @brief 操作GRAM内存(128*8char数组)
* @param[in] pen: 操作类型.
PEN_CLEAR: 设置为0x00
PEN_WRITE: 设置为0xff
PEN_INVERSION: 按位取反
* @retval none
*/
void OLED_operate_gram(pen_typedef pen)
{
uint8_t i, n;
for (i = 0; i < 8; i++)
{
for (n = 0; n < 128; n++)
{
if (pen == PEN_WRITE)
{
OLED_GRAM[n][i] = 0xff;
}
else if (pen == PEN_CLEAR)
{
OLED_GRAM[n][i] = 0x00;
}
else
{
OLED_GRAM[n][i] = 0xff - OLED_GRAM[n][i];
}
}
}
}
/**
* @brief 发送数据到OLED的GRAM
* @param[in] none
* @retval none
*/
void OLED_refresh_gram(void)
{
uint8_t i, n;
for (i = 0; i < 8; i++)
{
OLED_set_pos(0, i);
for (n = 0; n < 128; n++)
{
oled_write_byte(OLED_GRAM[n][i], OLED_DATA);
}
}
}
/**
* @brief 显示一个字符
* @param[in] row: 字符的开始行
* @param[in] col: 字符的开始列
* @param[in] chr: 字符
* @retval none
*/
void OLED_show_char(uint8_t row, uint8_t col, uint8_t chr)
{
uint8_t x = col * 6;
uint8_t y = row * 12;
uint8_t temp, t, t1;
uint8_t y0 = y;
chr = chr - ' ';
for (t = 0; t < 12; t++)
{
temp = asc2_1206[chr][t];
for (t1 = 0; t1 < 8; t1++)
{
if (temp&0x80)
OLED_draw_point(x, y, PEN_WRITE);
else
OLED_draw_point(x, y, PEN_CLEAR);
temp <<= 1;
y++;
if ((y - y0) == 12)
{
y = y0;
x++;
break;
}
}
}
}
/**
* @brief 显示一个字符串
* @param[in] row: 字符串的开始行
* @param[in] col: 字符串的开始列
* @param[in] chr: 字符串
* @retval none
*/
void OLED_show_string(uint8_t row, uint8_t col, uint8_t *chr)
{
uint8_t n =0;
while (chr[n] != '\0')
{
OLED_show_char(row, col, chr[n]);
col++;
if (col > 20)
{
col = 0;
row += 1;
}
n++;
}
}
Le processus d'affichage est le suivant :
1. Initialisez le module OLED, appelez OLED_init
2. Faites fonctionner le tableau GRAM dans stm32 via la fonction de caractère d'affichage
3. Appelez la fonction OLED_refresh_gram pour transférer les données GRAM vers le GRAM du module OLED pour affichage.
fonction principale
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM4_Init();
MX_I2C1_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_1); //初始化BUZZER
HAL_TIM_Base_Start_IT(&htim3); //开启定时器3中断
OLED_init(); //OLED初始化
// Solitary_brave();
OLED_operate_gram(PEN_CLEAR);
OLED_show_string(0,6,"LRJ_ROBOT");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(tim3_delay.count_10ms != tim3_delay.last_count_10ms)
{
GPIO_PinState pin_state = HAL_GPIO_ReadPin(LEDD_GPIO_Port, LEDD_Pin);//获取LED电平
OLED_printf(2,5,"LED_PIN = %d",pin_state);
tim3_delay.last_count_10ms = tim3_delay.count_10ms;
}
if(tim3_delay.count_400ms != tim3_delay.last_count_400ms)
{
OLED_refresh_gram();//屏幕刷新 400ms
HAL_GPIO_TogglePin(LEDD_GPIO_Port, LEDD_Pin);
tim3_delay.last_count_400ms = tim3_delay.count_400ms;
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
L'écran OLED affiche les changements de niveau de LED en temps réel