Вообщем напрягать меня стало использование 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
1 2 3 4 5 6 7 8 9 10 11 12 13 |
#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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
#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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
#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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
#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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#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.