prefacio
En el capítulo anterior, aprendí sobre la comunicación en serie y los temporizadores. En este capítulo, se presentará la comunicación I2C y el módulo OLED se iluminará mediante la comunicación I2C. Dado que el módulo OLED admite múltiples métodos de comunicación, el proceso de comunicación I2C del módulo OLED utiliza principalmente paquetes secundarios en la capa de datos para lograr el propósito de clasificar los paquetes de datos para adaptarse a varios métodos de comunicación del OLED.
herramientas de preparación
Software: STM32CubeMx, Keil5 MDK
Hardware: placa central STM32F103C8T6, descargador ST_LINK, pantalla de 4 pines de comunicación OLEDI2C
El proyecto de este capítulo se ha subido a Baidu Netdisk y este enlace es válido de forma permanente.
Enlace: https://pan.baidu.com/s/13UiC3hnn84yIsA5N1nrmmg?pwd=w8cx
Código de extracción: w8cx
comunicación I2C
I2C es un bus serial síncrono de dos hilos, de dos vías y semidúplex desarrollado por PHILIPS. El sistema de dos cables significa que I2C solo necesita dos líneas de señal, una línea de datos SDA y la otra es la línea de reloj SCL. El bus I2C permite montar varios dispositivos maestros, pero el reloj del bus solo puede ser generado por un dispositivo maestro a la vez, y cada dispositivo conectado al bus debe tener una dirección I2C única, y el dispositivo esclavo puede ser direccionado. por el dispositivo maestro. La comunicación I2C tiene varias clases de señales:
Señal de inicio S: cuando SCL está en un nivel alto, SDA pasa de un nivel alto a un nivel bajo, lo que representa el inicio de la transmisión de datos.
Señal final P: cuando SCL está en un nivel alto, SDA pasa de un nivel bajo a un nivel alto, lo que representa el final de la transmisión de datos.
Señal de datos: la señal de datos transmite 8 bits de datos cada vez, y cada bit de datos se transmite dentro de un ciclo de reloj. Cuando SCL está en un nivel alto, el nivel de la línea de datos SDA debe ser estable. Cuando SCL está en un nivel bajo nivel, en este momento, el nivel en la línea de datos SDA puede cambiar.
Señal de respuesta ACK/NACK: La señal de respuesta es que el maestro envía datos de 8 bits y el esclavo envía un nivel bajo al maestro, lo que indica que los datos han sido aceptados.
El proceso de transmisión I2C común para leer los datos del sensor se muestra en la siguiente tabla:
Todo el proceso de comunicación I2C se entiende como el proceso de envío y recepción de entrega urgente. La dirección I2C del dispositivo se entiende como la dirección del gabinete expreso de la escuela. Los dígitos de lectura y escritura representan el envío y la firma para entrega urgente. Firmado para mensajería . Todo el proceso es como ir al gabinete de mensajería de la escuela (dirección I2C esclava), enviar o firmar por el servicio de mensajería (datos) para el número de gabinete (dirección de registro).
Configuración de IIC en CubeMx
1. Busque I2C1 en conectividad,
2. Configure como I2C,
3. Configure como modo rápido,
4. Otros permanecen predeterminados.
Genere código y abra el proyecto.
Agregue el siguiente código al proyecto
/**
* @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);
}
Según el método de comunicación de OLED, es necesario indicar el tipo de datos en el primer byte, si es un comando de control, debe enviar 0x00, y si es un comando de datos, debe enviar 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 función OLED_init, que configura principalmente los parámetros OLED, pasa OLED_CMD llamando a oled_write_byte y transmite comandos de control para completar la configuración.
/**
* @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++;
}
}
El proceso de visualización es el siguiente:
1. Inicialice el módulo OLED, llame a OLED_init
2. Opere la matriz GRAM en stm32 a través de la función de caracteres de visualización
3. Llame a la función OLED_refresh_gram para transferir los datos GRAM a la GRAM del módulo OLED para su visualización.
función principal
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 */
}
La pantalla OLED muestra los cambios de nivel de LED en tiempo real