I2c STM32
I2c STM32
• Las dos líneas de comunicación corresponden a reloj (SCL) y datos (SDA). Las
transferencias son por tanto semi-dúplex.
• En el bus debe existir al menos un dispositivo Maestro que genera la señal de reloj
y uno o varios Esclavos que reciben tal señal SCL.
• Cada dispositivo esclavo conectado al bus tiene asignada una dirección única
codificada en 7 (ó en 10 bits de manera opcional)
• El FIN de transferencia es por transición de “0” a “1” en SDA cuando SCL está a
“1”
Interface I2C
• En cualquiera de los casos, el Maestro será el que genere la señal de reloj en SCL
•Se retiene la generación de reloj del Maestro porque el Esclavo mantiene SCL
a 0 mientras prepara el envío.
I2C ESCLAVO: Transmisión (II)
Si por el contrario, se recibe un ACK del Maestro, el Esclavo debe continuar enviando
bytes, para lo cual debe cargar el nuevo dato y liberar la línea SCL con CKP=1
I2C en el bus ESCLAVO: “Llamada general” I2C
•La “llamada general” en el interface I2C es un envío con una dirección válida para
todos los esclavos que se encuentren presentes en el bus. La dirección que coloca el
Maestro consiste en 7 ceros seguido de R/W = 0. En este caso, todos los Esclavos
deberían responder con el pulso de reconocimiento ACK.
Interface I2C
Interface I2C
Para el Envío y Recepción de bytes de datos se usan la funciones provistas dentro de la librería HAL.
• FUNCIONES POR INTERRUPCION PARA LA LECTURA Y ESCRITURA SOBRE MEMORIA PARA MAESTRO
• HAL_I2C_Mem_Write_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize,
uint8_t *pData, uint16_t Size);
• HAL_I2C_Mem_Read_IT(I2C_HandleTypeDef *hi2c, uint16_t DevAddress, uint16_t MemAddress, uint16_t MemAddSize,
uint8_t *pData, uint16_t Size);
SOLUCIÓN : CÓDIGO
La memoria EEPROM i2c tiene la siguiente dirección: 1010 E2
E1 E0. Las funciones de i2c de la librería HAL necesitan que #include "stm32f1xx_hal.h"
la dirección del dispositivo se recorran a la izquierda una #include <string.h>
posición, por lo cual la dirección seria: 1010 E2 E1 E0 0. #include <stdlib.h>
Los valores de E2 E1 E0 se define mediante hardware ya
GPIO_InitTypeDef GPIO_InitStruct;
que son tres pines del circuito. Si se conectan a tierra como UART_HandleTypeDef huart1;
muestra la figura la dirección sería: 1010 0000 = 0xA0 I2C_HandleTypeDef hi2c1;
if(strcmp(wmsg, rmsg) == 0)
{
while(1)
{
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_10);
HAL_Delay(100);
}
}
while(1);
}
Interface I2C void GPIO_Init(void)
{
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE(); //IMPORTANTE!!!!!
__HAL_RCC_GPIOB_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}
Interface I2C
{ {
__HAL_RCC_USART1_CLK_ENABLE(); hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
huart1.Instance = USART1; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
huart1.Init.BaudRate = 9600;
hi2c1.Init.OwnAddress1 = 0;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
huart1.Init.Mode = UART_MODE_TX_RX; hi2c1.Init.OwnAddress2 = 0;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
HAL_UART_Init(&huart1); __HAL_AFIO_REMAP_I2C1_ENABLE();
} __HAL_RCC_I2C1_CLK_ENABLE();
__HAL_RCC_I2C1_FORCE_RESET();
__HAL_RCC_I2C1_RELEASE_RESET();
HAL_I2C_Init(&hi2c1);
}
Interface I2C
Hardware del Módulo adaptador LCD a I2C
El Módulo adaptador LCD a I2C que se usará se
basa en el Expansor de Entradas y Salidas
digitales controlado por el PCF8574. Este módulo
se usa para controlar un LCD Alfanumérico.
La dirección I2C, de 7 bits, por defecto del
módulo puede ser 0x3F o en otros casos
0x27. Es importante identificar la dirección I2C
del modulo. Si existe la necesidad de usar más
de un LCD se puede modificar la dirección I2C
del modulo adaptador soldando los puentes A0,
A1 y A2 presentes en el módulo, estos tres
puentes son los bits menos significativos de la
dirección I2C del módulo. La dirección 0x3F en
binario sería: 0|0|1|1|1|A2|A1|A0 y la dirección
0x27: 0|0|1|0|0|A2|A1|A0. Por defecto A0, A2,
A1 valen 1 pero si soldamos los puentes, estos
se conectan a tierra teniendo un valor 0. Por
ejemplo si soldamos los tres puentes la nueva
dirección sería 0|0|1|0|0|0|0|0 (0x20), para un
chip que anteriormente era 0x27.
Interface I2C
Hardware del Módulo adaptador LCD a I2C
El Módulo adaptador LCD a I2C que se usará se
basa en el Expansor de Entradas y Salidas
digitales controlado por el PCF8574. Este módulo
se usa para controlar un LCD Alfanumérico.
La dirección I2C, de 7 bits, por defecto del
módulo puede ser 0x3F o en otros casos
0x27. Es importante identificar la dirección I2C
del modulo. Si existe la necesidad de usar más
de un LCD se puede modificar la dirección I2C
del modulo adaptador soldando los puentes A0,
A1 y A2 presentes en el módulo, estos tres
puentes son los bits menos significativos de la
dirección I2C del módulo. La dirección 0x3F en
binario sería: 0|0|1|1|1|A2|A1|A0 y la dirección
0x27: 0|0|1|0|0|A2|A1|A0. Por defecto A0, A2,
A1 valen 1 pero si soldamos los puentes, estos
se conectan a tierra teniendo un valor 0. Por
ejemplo si soldamos los tres puentes la nueva
dirección sería 0|0|1|0|0|0|0|0 (0x20), para un
chip que anteriormente era 0x27.
Interface I2C
Interface I2C Conexión con el LCD
Vcc
ENVIAR DE STRING
ENVIAR DE FLOTANTE
void lcd_enviar_float (float dato, int numerodedigitos)
{
char flotante[12];
sprintf (flotante,"%f", dato);
for (int i=0; i< numerodedigitos; i++)
{
lcd_enviar_dato (flotante[i]);
}
}
Interface I2C FUNCIONES DEL LCD i2C
ENVIAR ENTERO
void lcd_enviar_int (int dato)
{
char numero[12];
sprintf (numero,"%d", dato);
lcd_enviar_string (numero);
}
}
MOVER CURSOR
void lcd_a_xy(uint8_t x, uint8_t y)
{
uint8_t direccion[] = {0x80, 0xC0, 0x94, 0xD4};
lcd_enviar_cmd(direccion[y-1] + (x-1));
HAL_Delay(1);
}
Interface I2C Funciones de control para el LCD
Para habilitar el modo de 4 bits, el controlador del LCD también nos
INICIALIZACION DEL LCD
permite la siguiente secuencia
void lcd_init (void)
{
// inicialización de 4 bits
HAL_Delay(50); // espera >40ms
lcd_enviar_cmd (0x30);
HAL_Delay(5); // espera >4.1ms
lcd_enviar_cmd (0x30);
HAL_Delay(1); // espera >100us
lcd_enviar_cmd (0x30);
HAL_Delay(10);
lcd_enviar_cmd (0x20); // modo de 4 bits
HAL_Delay(10);
Programa ejemplo que muestra la utilización de las funciones i2c para el madejo del LCD por medio del
C.I. PCF8574
#include "main.h"
#define DIR_ESCLAVO_LCD 0x4E // 0x4E es la dirección por defecto del LCD i2c
I2C_HandleTypeDef hi2c1;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
//Prototipo de las funciones i2c del LCD
void lcd_enviar_cmd (char cmd);
void lcd_enviar_dato (char dato);
void lcd_init (void);
void lcd_enviar_string (char *str);
void lcd_a_xy(uint8_t x, uint8_t y);
void lcd_enviar_int (int dato);
void lcd_enviar_float (float dato, int numerodedigitos);
Interface I2C Ejemplo del uso del LCD con I2C
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_I2C1_Init();
lcd_init ();
while (1)
{
float numero=99.00;
for (uint8_t i=0;i<10 ;i++ )
{
lcd_a_xy(1,2); // cursor en la posición (1,2)
lcd_enviar_string ("contando: ");
lcd_enviar_int (i); // se imprime el valor del contador i
HAL_Delay(500); // retardo de medio segundo
}
for (uint8_t i=1;i<10 ;i++ ) // primer valor de i=1 por que no se divide entre 0
{
lcd_a_xy(1,2); // cursor en la posición (1,2)
lcd_enviar_string ("contando: ");
numero=numero/i;
lcd_enviar_float (numero,4); // se imprime el numero flotante con 4 caracteres incluyendo el punto
HAL_Delay(500); // retardo de medio segundo
}
lcd_a_xy(1,2); // cursor en la posición (1,2)
lcd_enviar_string (" "); // 16 espacios en blanco para borrar la 2da línea
}
}