LCD1602 + pcf8574 (I2C) + STM32F0
Hello.
I have some problem with LCD1602+pcf8574 (I2C) and STM32F0.
I experience the following bugs
1) When I try to display more than three symbols they seem to be ignored
2) If I try to display three symbols, I have to flush the firmware twice(one directly after another) in order to display changes on the LCD1602 screen
It seems that there is some overrun(????), but I can't figure out where.
What am I doing wrong?
Help me, please.
main.c
&sharpinclude 'stm32f0xx.h'
&sharpinclude 'i2c_lcd.h'
&sharpdefine I2C1_OWN_ADDRESS (0x27)
int main(void) {
SystemInit();
gpioInit();
i2cInit();
InitDelayTIM6();
delay_init();
lcd_Init();
lcd_PrintC('ABC'); //if I try to print ABCD nothing happends; Another three letter can be displayed
while(1) { }
}
void gpioInit(void) {
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;
GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER6 | GPIO_MODER_MODER7)) \ | (GPIO_MODER_MODER6_1 | GPIO_MODER_MODER7_1);GPIOB->OTYPER |= GPIO_OTYPER_OT_6 | GPIO_OTYPER_OT_7;
GPIOB->AFR[0] = (GPIOB ->AFR[0] &~ (GPIO_AFRL_AFRL6 | GPIO_AFRL_AFRL7))\
| (1 << (6 * 4)) | (1 << (7 * 4));}void i2cInit(void) {
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;I2C1->CR1 &= ~(I2C_CR1_PE) ;
/* Timing register value is computed with the AN4235 xls file,
Standard Mode @50kHz with I2CCLK = 48MHz, rise time = 100ns, fall time = 30ns */I2C1->TIMINGR = (uint32_t) 0x205078C1;
I2C1->CR1 |= I2C_CR1_PE ;
I2C1->CR2 |= I2C_CR2_AUTOEND | (1<<16) | (I2C1_OWN_ADDRESS<<1);
}
i2c_lcd.c
&sharpinclude 'i2c_lcd.h'
&sharpinclude 'stm32f0xx_i2c.h' // this one is not used
uint8_t backlightState = 1;
void lcd_PrintC(const uint8_t *str) {
uint8_t i; while (i = *str++){ lcd_Data(i);TIM6delay_ms(2);
}}void lcd_Init(void) {
TIM6delay_ms(50);
lcd_FirstCommand();lcd_Command(0x28);// 4bit 2 lines, 5x8 font. Page 8 Function Set. Page 9 Top.
lcd_Command(0x08); // display off entirely. Page 6, row 4. Page 8 Display On/Off
lcd_Command(0x06); //Page 6 Row 3
lcd_Command(0x01);// Clear display. Page 6, first row. Page 7 Clear Display.
lcd_Command(0x02); //Return home
lcd_Command(0x80);
lcd_Command(0x0E);
TIM6delay_ms(1000);
}void lcd_Send(uint8_t data) {
while((I2C2->ISR & I2C_ISR_BUSY) == (I2C_ISR_BUSY));
while(!((I2C1->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE))); // Check Tx empty
I2C1->TXDR = data; // Byte to send
I2C1->CR2 |= I2C_CR2_START; // Go
while(!((I2C1->ISR & I2C_ISR_TXE) == (I2C_ISR_TXE)));
while((I2C2->ISR & I2C_ISR_BUSY) == (I2C_ISR_BUSY));
}
void lcd_FirstCommand(void) {// I am sending 0x33 followed by 0x32. The delays are from datasheet
// the data is sent as EN changes from High to Low
lcd_Send(0x03 |(backlightState & 0x01) << BL);
lcd_Send(0x03 | (1 << EN));
TIM6delay_us(2);
lcd_Send(0x03|((backlightState & 0x01) << BL));
TIM6delay_us(4100);
lcd_Send(0x03|(backlightState & 0x01) << BL);
lcd_Send(0x03 | (1 << EN));
TIM6delay_us(2);
lcd_Send(0x03|((backlightState & 0x01) << BL));
TIM6delay_us(100);
lcd_Send(0x03|((backlightState & 0x01) << BL));
lcd_Send(0x03 | (1 << EN));
TIM6delay_us(2);
lcd_Send(0x03|((backlightState & 0x01) << BL));
lcd_Send(0x02|((backlightState & 0x01) << BL));
lcd_Send(0x02 | (1 << EN));
TIM6delay_us(2);
lcd_Send(0x02|((backlightState & 0x01) << BL)); }
void lcd_Command(uint8_t com) {
uint8_t data = 0;
data |= (backlightState & 0x01) << BL;
data |= (((com & 0x10) >> 4) << DB4);
data |= (((com & 0x20) >> 5) << DB5);
data |= (((com & 0x40) >> 6) << DB6);
data |= (((com & 0x80) >> 7) << DB7);
lcd_Send(data);
lcd_Send(data | (1 << EN));
TIM6delay_us(2);
lcd_Send(data);
data = 0;
data |= (backlightState & 0x01) << BL;
data |= (((com & 0x01) >> 0) << DB4);
data |= (((com & 0x02) >> 1) << DB5);
data |= (((com & 0x04) >> 2) << DB6);
data |= (((com & 0x08) >> 3) << DB7);
lcd_Send(data);
lcd_Send(data | (1 << EN));
TIM6delay_us(2);
lcd_Send(data);}
void lcd_Backlight(uint8_t state) {
backlightState = (state & 0x01) << BL;
lcd_Send(backlightState);
}
void lcd_Data(uint8_t com) {
uint8_t data = 0;
// this differes 'data' from 'command' . Data - symbol to be displayed
data |= (1 << RS);
data |= (backlightState & 0x01) << BL;
data |= (((com & 0x10) >> 4) << DB4);
data |= (((com & 0x20) >> 5) << DB5);
data |= (((com & 0x40) >> 6) << DB6);
data |= (((com & 0x80) >> 7) << DB7);
lcd_Send(data);
lcd_Send(data | (1 << EN));
TIM6delay_us(2);
lcd_Send(data);
data = 0;
data |= (1 << RS);
data |= (backlightState & 0x01) << BL;
data |= (((com & 0x01) >> 0) << DB4);
data |= (((com & 0x02) >> 1) << DB5);
data |= (((com & 0x04) >> 2) << DB6);
data |= (((com & 0x08) >> 3) << DB7);
lcd_Send(data);
lcd_Send(data | (1 << EN));
TIM6delay_us(2);
lcd_Send(data);
}
I am sorry for such a long question. Thank You very much for Your time!
#lcd1602 #i2c #stm32f0 #funny-bug