Вообщем напрягать меня стало использование LCD дисплея, на контроллере hd44780 с использованием стандартного подключения, даже 4-битный режим не спасение уже.
Нашел весьма элегантное на мой взгляд решение, использовать всем известный модуль на микросхеме PCF8574AT.
Купить модуль: ссылка
Вот он:
Устройство микросхемы:
К контроллеру она подключается по I2C интерфейсу. К выводам P0-P7 подключается дисплей.
- P0 — RS
- P1 — RW
- P2 — E
- P3 — УПРАВЛЕНИЕ ПОДСВЕТКОЙ >если 1 то горит подсветка<
- P4 — D4
- P5 — D5
- P6 — D6
- P7 — D7
Выводы A0-A2 предназначены для установки адреса устройства, в исходном состоянии >без перемычек< адрес получается 0x3F.
Таблица для формирования адреса:
На шину I2C можно вешать много устройств это наверное главное из ее преимуществ, можно подключить несколько таких модулей задав установкой перемычек каждому свой адрес.
Запуск:
Первый STM контроллер с которого я начал свой путь в мир современных микроконтроллеров, оказался STM32F051R8T6. Все что я в нем использовал из периферии, трудностей не вызывало, но решил вдруг использовать I2C и тут началось. Ни как ни смог его заставить работать, вообщем плюнул и купил платку с контроллером STM32F103C8T6 использовал стандартную библиотеку StdPeriph и все заработало.
Код:
Проект создан в среде CooCox CoIDE
Настройка I2C:
i2c.h
#ifndef I2C_H #define I2C_H #include "stm32f10x.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "stm32f10x_i2c.h" void I2C_Configuration(void); void PCF8574AT_WriteByte(uint8_t data,uint8_t adress); #endif
i2c.c
#include "i2c.h" I2C_InitTypeDef i2c; GPIO_InitTypeDef gpio; void I2C_Configuration(void) { RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); i2c.I2C_ClockSpeed = 100000; i2c.I2C_Mode = I2C_Mode_I2C; i2c.I2C_DutyCycle = I2C_DutyCycle_2; i2c.I2C_OwnAddress1 = 0x15; i2c.I2C_Ack = I2C_Ack_Enable; i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_Init(I2C1, &i2c); gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; gpio.GPIO_Mode = GPIO_Mode_AF_OD; gpio.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &gpio); I2C_Cmd(I2C1, ENABLE); } void PCF8574AT_WriteByte(uint8_t data, uint8_t adres) { while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); I2C_GenerateSTART(I2C1, ENABLE); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)); I2C_Send7bitAddress(I2C1, adres<<1, I2C_Direction_Transmitter); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)); I2C_SendData(I2C1,data); while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); I2C_GenerateSTOP(I2C1, ENABLE); }
Библиотека для HD44780:
hd44780_i2c.h
#ifndef HD44780_I2C_H #define HD44780_I2CH #include "i2c.h" #include "delay.h" #define RS 0x01 #define RW 0x02 #define E 0x004 #define LH 0xF0 #define ON_BLACKLIGHT 0x08 void LCD_init(void); void LCD_send_byte (unsigned char data, uint8_t com, uint8_t dat); void LCD_com(unsigned char data); void LCD_dat(unsigned char data); void LCD_puts(char *p); void LCD_gotoxy(int row, char col); void LCD_clear(void); void LCD_own_symbols(void); void LCD_hor_graph(float value, char row); void LCD_vert_graph(char value, char row, char col); #endif
hd44780_i2c.c
#include "hd44780_i2c.h" const unsigned char array_LCD[]={0x80, 0xC0, 0x94, 0xD4}; void LCD_com(unsigned char data) { LCD_send_byte (data,0x00,0x00); } void LCD_dat(unsigned char data) { LCD_send_byte (data,0x00,RS); } void LCD_send_byte (unsigned char data, uint8_t com, uint8_t dat) { uint8_t buff; buff = data; buff = (buff & LH)|E|com|dat|ON_BLACKLIGHT; PCF8574AT_WriteByte(buff,0x3f); buff &= ~E; PCF8574AT_WriteByte(buff,0x3f); delay_us(40); buff = data; buff = (buff <<4)|E|com|dat|ON_BLACKLIGHT; PCF8574AT_WriteByte(buff,0x3f); buff &= ~E; PCF8574AT_WriteByte(buff,0x3f); } void LCD_init(void) { delay_ms(20); delay_ms(20); LCD_com(0x33); delay_ms(7); LCD_com(0x32); delay_us(100); LCD_com(0x28); LCD_com(0x08); LCD_com(0x01); delay_ms(20); LCD_com(0x06); LCD_com(0x0D); } void LCD_puts(char *p) { while(*p) LCD_dat(*p++); } void LCD_gotoxy(int row, char col) { LCD_com(array_LCD[row]+col); } void LCD_clear(void) { LCD_com(0x01); delay_ms(2); }
main.c
#include "main.h" int main(void) { cconf_init(); delay_init(); I2C_Configuration(); LCD_init(); LCD_com(0x0C); LCD_gotoxy(1, 0); LCD_puts("PCF8574AT ON"); }
main.h
#ifndef MAIN_H #define MAIN_H #include "stm32f10x.h" #include <stdint.h> #include <stdio.h> #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" #include "clock_config.h" #include "stm32f10x_i2c.h" #include "delay.h" #include "i2c.h" #include "hd44780_i2c.h" #endif
Реализация задержки:
delay.h
#ifndef DELAY_H #define DELAY_H #include "stm32f10x.h" #include "stm32f10x_rcc.h" void delay_init(void); void delay_us(unsigned int delay); void delay_ms(unsigned int delay); #endif
delay.c
#include "delay.h" #define F_APB1 8000000 void delay_init(void) { RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; } void delay_ms(unsigned int delay) { TIM2->PSC = F_APB1/1000+1; TIM2->ARR = delay; TIM2->EGR |= TIM_EGR_UG; TIM2->CR1 |= TIM_CR1_CEN | TIM_CR1_OPM; while ((TIM2->CR1&TIM_CR1_CEN)!=0); } void delay_us(unsigned int delay) { TIM2->PSC = F_ABP1/1000000-1; TIM2->ARR = delay; TIM2->EGR |= TIM_EGR_UG; TIM2->CR1 |= TIM_CR1_CEN | TIM_CR1_OPM; while ((TIM2->CR1&TIM_CR1_CEN)!=0); }
На этом все дорогие друзья, дерзайте и используйте во благо.
Добрый день! А можно еще выложить недостающие здесь файлы? Т.е. заголовочные файлы main.h и delay.h, и, собственно, реализацию самого модуля, реализующего задержки — delay.c. Спасибо.
Самому написать ни как?
Можно и самому написать, но мне была интересна именно ваша реализация, к тому же вариант с использованием таймера не единственно возможный… И я увидел именно то, что хотел увидеть —
«чистую» реализацию без использования функций HAL и т.п. Когда только начинаешь осваивать STM32, то готовые примеры сильно экономят время.
P.S.: в названии макроса «F_ABP1» опечатка, название шины — APB1 (Advanced Peripheral Bus), а не «ABP1». Это, конечно же, мелочи, но все же.
Всякие генераторы кода не приемлю, хватило в свое время CodeVisionAvr.