STM32 Библиотека для работы с модулем PCF8574AT

Автор: | 14.08.2017

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

 

 

На этом все дорогие друзья, дерзайте и используйте во благо.

ПОДДЕРЖАТЬ ПРОЕКТ

 

 

 

STM32 Библиотека для работы с модулем PCF8574AT: 4 комментария

  1. Dmitry

    Добрый день! А можно еще выложить недостающие здесь файлы? Т.е. заголовочные файлы main.h и delay.h, и, собственно, реализацию самого модуля, реализующего задержки — delay.c. Спасибо.

  2. yriy Автор записи

    Самому написать ни как?

  3. Dmitry

    Можно и самому написать, но мне была интересна именно ваша реализация, к тому же вариант с использованием таймера не единственно возможный… И я увидел именно то, что хотел увидеть —
    «чистую» реализацию без использования функций HAL и т.п. Когда только начинаешь осваивать STM32, то готовые примеры сильно экономят время.

    P.S.: в названии макроса «F_ABP1» опечатка, название шины — APB1 (Advanced Peripheral Bus), а не «ABP1». Это, конечно же, мелочи, но все же.

  4. yriy Автор записи

    Всякие генераторы кода не приемлю, хватило в свое время CodeVisionAvr.

Добавить комментарий