Вообщем напрягать меня стало использование 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.