Учебный курс. Подключение LCD к микроконтроллеру. Разбиваем программу на модули
Зачем разбивать программу на модули/файлы
Возможность повторного использования кода
Возможность раздельной компиляции
Возможность совместной работы над проектом
Область видимости переменных/функций, находящихся в разных модулях
extern unsigned char key;
extern unsigned char key = 0; //неправильно. Вызовет ошибку!
static unsigned char LCD_CheckBF(void)
{
//тело функции
}
Попытка использовать эту функцию в другом файле вызовет ошибку компиляции.
Как разбить программу на модули
Открываем наш старый проект.
Создаем в IARe два файла – lcd_lib.h и lcd_lib.c.
Сохраняем файлы в папке проекта.
Добавляем файл lcd_lib.c в наш проект. (Правой кнопкой мышки кликаем в workspace`e и в открывшемся меню выбираем Add > Add files…).
В lcd_lib.c с помощью директивы include подключаем заголовочный файл -
#include “lcd_lib.h”.
В lcd_lib.h добавляем строчки
#ifndef LCD_LIB_H
#define LCD_LIB_H
#endif
Теперь у нас есть своего рода заготовка и нам нужно ее наполнить содержимым.
Содержимое заголовочного файла
Подключаемые библиотеки
#include <ioavr.h>
#include <intrinsics.h>
Макроопределения портов
//порт к которому подключена шина данных ЖКД
#define PORT_DATA PORTD
#define PIN_DATA PIND
#define DDRX_DATA DDRD
//порт к которому подключены управляющие выводы ЖКД
#define PORT_SIG PORTB
#define PIN_SIG PINB
#define DDRX_SIG DDRB
//Номера выводов к которым подключены управляющие выводы ЖКД
#define RS 5
#define RW 6
#define EN 7
Макроопределение тактовой частоты микроконтроллера
#define F_CPU 8000000
Прототипы функций
void LCD_Init(void); //инициализация портов и жкд
void LCD_WriteData(unsigned char data); //выводит байт данных на жкд
void LCD_WriteCom(unsigned char data); //посылает команду жкд
Прототип функции – это объявление, содержащее тип возвращаемого значения, название функции и ее параметры.
Содержимое файла lcd_lib.c
Макросы для работы с битами и макросы для программных задержек
#define ClearBit(reg, bit) reg &= (~(1<<(bit)))
#define SetBit(reg, bit) reg |= (1<<(bit))
#define _delay_us(us) __delay_cycles((F_CPU / 1000000) * (us));
#define _delay_ms(ms) __delay_cycles((F_CPU / 1000) * (ms));
Определение всех функций
//функция записи команды
void LCD_WriteCom(unsigned char data)
{
ClearBit(PORT_SIG, RS); //установка RS в 0 - команды
PORT_DATA = data; //вывод данных на шину индикатора
SetBit(PORT_SIG, EN); //установка E в 1
_delay_us(2);
ClearBit(PORT_SIG, EN); //установка E в 0 - записывающий фронт
_delay_us(40);
}
//функция записи данных
void LCD_WriteData(unsigned char data)
{
SetBit(PORT_SIG, RS); //установка RS в 1 - данные
PORT_DATA = data; //вывод данных на шину индикатора
SetBit(PORT_SIG, EN); //установка E в 1
_delay_us(2);
ClearBit(PORT_SIG, EN); //установка E в 0 - записывающий фронт
_delay_us(40);
}
//функция инициализации
void LCD_Init(void)
{
DDRX_DATA = 0xff;
PORT_DATA = 0xff;
DDRX_SIG = 0xff;
PORT_SIG |= (1<<RW)|(1<<RS)|(1<<EN);
ClearBit(PORT_SIG, RW);
_delay_ms(40);
LCD_WriteCom(0x38); //0b00111000 - 8 разрядная шина, 2 строки
LCD_WriteCom(0xf); //0b00001111 - дисплей, курсор, мерцание включены
LCD_WriteCom(0x1); //0b00000001 - очистка дисплея
_delay_ms(2);
LCD_WriteCom(0x6); //0b00000110 - курсор движется вправо, сдвига нет
}
Подключаем библиотеку к проекту
В принципе все готово.
Сохраняем оба файла.
Подключаем нашу библиотеку к файлу main.c.
#include "lcd_lib.h"
Убираем из него все лишнее. И добавляем вывод слова “Test.”
Вот что должно получиться.
#include <ioavr.h>
#include "lcd_lib.h"
int main( void )
{
LCD_Init();
LCD_WriteData('T');
LCD_WriteData('e');
LCD_WriteData('s');
LCD_WriteData('t');
LCD_WriteData('2');
while(1);
return 0;
}
Компилируем проект… У меня все прошло без ошибок. Надеюсь у вас тоже.
Ну а это структура нашего нового проекта.
P.S.:
Если вы работаете в WINAVR и ваш проект состоит из нескольких файлов, компилятору нужно указывать их вручную. Делается это в Makefile – просто вписываем название файлов через пробел.
# List C source files here. (C dependencies are automatically generated.)
SRC = $(TARGET).c lcd_lib.c
Файлы
Проект для IARa. Проект для WINAVR.
Comments
#define port_rs PORTB_PORTB5
соответственно :
port_rs = 0;
port_rs = 1;
( iar avr 5.40 )
пример объявления;
extern volatile unsigned char raz;
extern unsigned char keyState;
номера битов порта вывода. Т.е.
#define RS 4
#define RW 5
#define EN 6
либо править схему. Повнимательней, пожалуйста. Начинающим довольно трудно выцеплять такие баги.
А в целом - молодца!!! Хороший материал.
Quote: Но в lcd_lib.h нет упоминания о файле lcd_lib.с. Как компилятор "узнает", что исходный текст в последнем и его надо обрабатывать?
цитата:
Добавляем файл lcd_lib.c в наш проект. (Правой кнопкой мышки кликаем в workspace`e и в открывшемся меню выбираем Add > Add files…).
А непосредственно в самом хэдере мы о нем ничего не упоминаем. Так и надо? Или все же есть способ, без использования правой кнопки мыши?
Code:
#include "LCD.c"
А в Codevision-е видны. Отличный от других?
- упорядоченная структура программы,
- отделение интерфейса модуля от его реализации,
- возможность повторного использования кода.
Теоретически да, нужно перекомпилирова ть один модуль. Но потом нужно еще собрать весь проект (этим занимается линкер).
Можно перенести, но это равносильно написанию кода в одном файле.
Ну примерно так
есть интерфейс i2c - для него написана библиотека, которая реализует функции для работы с ним.
есть микросхема DS1307 - для нее написана своя библиотека, которая реализует функции для работы с ней и из нее вызывается библиотека для i2c.
Также можно для spi, 1-wire.
RSS feed for comments to this post