Программирование микроконтроллеров. Часть 5
И снова здравствуйте. Настает такой момент, когда код становиться большим и навигация по нему очень затруднена. Приходится постоянно скролить и искать тот или иной участок в коде, что в свою очередь очень раздражает. От таких неудобств можно избавиться довольно простым способом – это оформить отдельные участки кода в отдельные функции, которые будут находиться в других файлах и по мере необходимости их оттуда можно вызвать.
Приступим. Для этого нам понадобиться код из прошлого урока, его и будем «расчленять». Возьмем самое начало кода:
#define F_CPU 8000000UL //Рабочая частота МК (8МГц)
#include <avr/io.h>
#include <stdio.h> //Нужна для работы с текстом
#include <stdlib.h> //заголовочный файл стандартной библиотеки языка Си
#include <util/delay.h> //для _delay_ms()
#define e1 PORTB|=0b00001000 //установка линии E в 1
#define e0 PORTB&=0b11110111 //установка линии E в 0
#define rs1 PORTB|=0b00000100 //установка линии RS в 1 (данные)
#define rs0 PORTB&=0b11111011 //установка линии RS в 0 (команда)
И поместим его в отдельный заголовочный файл main.h. Для этого нужно в дереве проектов щёлкнуть правой кнопкой по нашему проекту и выбирать в контекстном меню субменю Add, а в нём уже выбирать пункт New Item. И в открывшемся диалоге выбирать тип файла, который мы будем создавать, "Include File" И внизу в имени файла изменить IncFile1 на main, затем нажать кнопку Add. Будет создан файл с таким содержимым:
#ifndef MAIN_H_
#define MAIN_H_
#endif /* MAIN_H_ */
В данный файл нужно поместить все подключения всех заголовочных файлов библиотек и все макроподстановки, а в файле main.c всё это удалить. Файл main.h должен выглядеть так:
#ifndef MAIN_H_
#define MAIN_H_
#define F_CPU 8000000UL //Рабочая частота МК (8МГц)
#include <avr/io.h>
#include <stdio.h> //Нужна для работы с текстом
#include <stdlib.h> //заголовочный файл стандартной библиотеки языка Си
#include <util/delay.h> //для _delay_ms()
#define e1 PORTB|=0b00001000 //установка линии E в 1
#define e0 PORTB&=0b11110111 //установка линии E в 0
#define rs1 PORTB|=0b00000100 //установка линии RS в 1 (данные)
#define rs0 PORTB&=0b11111011 //установка линии RS в 0 (команда)
#endif /* MAIN_H_ */
В самом начале файла main.c чтобы подключить файл main.h нужно написать всего одну строку: #include "main.h"
Сохраняем, компилируем и проверяем проект. Все должно работать.
Теперь необходимо весь код относящийся к АЦП поместить в отдельный файл adc.c. В самом начале файла нужно добавить уже знакомую строку: #include "main.h"
, а в файле main.h добавить следующие строки:
void ADC_ini();
float ADC_convert (void);
Код файла adc.c:
#include "main.h"
//Инициализируем АЦП
void ADC_ini(){
ADCSRA |= (1<<ADEN) // Разрешение использования АЦП
|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//Делитель 128
ADMUX |= (0<<REFS1)|(0<<REFS0); //Подключен внешний опорный ион, внутренний ион выключен
ADMUX |= (0 << MUX0)|(0 << MUX1)|(0 << MUX2)|(0 << MUX3); // вход PC0
}
//Получаем данные с АЦП
float ADC_convert (void)
{
ADCSRA |= (1<<ADSC); //Начинаем преобразование
while((ADCSRA & (1<<ADSC))); //проверим закончилось ли аналого-цифровое преобразование
return (unsigned int) ADC;
}
Также вынесем все, что касается инициализации и вывода на экран LCD в отдельный файл lcd.c:
#include "main.h"
//Отправляем половину байта
void send_half_byte(unsigned char c)
{
c<<=4;
e1; //включаем линию Е
_delay_us(50);
PORTB&=0b00001111; //стираем информацию на входах DB4-DB7, остальное не трогаем
PORTB|=c;
e0; //выключаем линию Е
_delay_us(50);
}
void send_byte(unsigned char c, unsigned char mode)
{
if (mode==0) rs0;
else rs1;
unsigned char hc=0;
hc=c>>4;
send_half_byte(hc); send_half_byte(c);
}
//Передаем только данные
void send_char(unsigned char c)
{
send_byte(c,1);
}
//Задаем позицию
void set_pos(unsigned char x, unsigned y)
{
char adress;
adress=(0x40*y+x)|0b10000000;
send_byte(adress, 0);
}
//Выводим строку
void str_lcd (char str1[])
{
wchar_t n;
for(n=0;str1[n]!='\0';n++)
send_char(str1[n]);
}
//Инициализация LCD
void LCD_ini(void)
{
_delay_ms(15); //Ждем 15 мс
send_half_byte(0b00000011);
_delay_ms(4);
send_half_byte(0b00000011);
_delay_us(100);
send_half_byte(0b00000011);
_delay_ms(1);
send_half_byte(0b00000010);
_delay_ms(1);
send_byte(0b00101000, 0); //4бит-режим и 2 линии
_delay_ms(1);
send_byte(0b00001100, 0); //включаем изображение на дисплее, курсоры никакие не включаем
_delay_ms(1);
send_byte(0b00000110, 0); //курсор (хоть он у нас и невидимый) будет двигаться влево
_delay_ms(1);
}
Если в файле main.h не прописать все функции, то программа работать не будет. Делается это следующим образом: возьмем функцию:
void send_char(unsigned char c)
{
send_byte(c,1);
}
Скопируем void send_char(unsigned char c) в файл main.h и в конце добавим точку с запятой: void send_char(unsigned char c);. Это необходимо проделать со всеми функциями. Сохраняем, компилируем и проверяем проект. Все должно работать.
После всех манипуляций по «расчленению» кода файл main.c будет выглядеть так:
#include "main.h"
char string[10]; //Массив для временного хранения форматированного текста
//Инициализируем порты
void port_ini(void)
{
DDRD=0xff;
PORTD=0x00;
DDRB=0xFF;
PORTB=0x00;
}
//Главная функция
int main(void)
{
port_ini(); //Инициализируем порты
ADC_ini(); //Инициализируем АЦП
LCD_ini(); //Инициализируем АЦП
set_pos(2,0); //Устанавливаем курсор
str_lcd("Hello, Golos");
unsigned int u;
float V; // Переменная для выводимого значения. float так как у нас точность до 2 знаков.
while (1)
{
u = ADC_convert(); //Вызывем преобразование
V = (float) u*0.0048828; // Переводим в вольты
sprintf(string, "V = %1.2f", V); // форматируем
set_pos(0,1); //Выставляем курсор
str_lcd(string); //Выводим данные на дисплей
//проверяем считанное значение
if (u > 128)
PORTD = 0b00000001;
else
PORTD = 0b00000000;
if (u > 256)
PORTD = 0b00000011;
if (u > 384)
PORTD = 0b00000111;
if (u > 512)
PORTD = 0b00001111;
if (u > 640)
PORTD = 0b00011111;
if (u > 768)
PORTD = 0b00111111;
if (u > 896)
PORTD = 0b01111111;
if (u > 1020)
PORTD = 0b11111111;
_delay_ms(30);
}
}
Как видите код стал на много более читабельным, все лишнее убрано в отдельные файлы. Навигация по коду стала проще.
Код файла main.h:
#ifndef MAIN_H_
#define MAIN_H_
#define F_CPU 8000000UL //Рабочая частота МК (8МГц)
#include <avr/io.h>
#include <stdio.h> //Нужна для работы с текстом
#include <stdlib.h> //заголовочный файл стандартной библиотеки языка Си
#include <util/delay.h> //для _delay_ms()
#define e1 PORTB|=0b00001000 //установка линии E в 1
#define e0 PORTB&=0b11110111 //установка линии E в 0
#define rs1 PORTB|=0b00000100 //установка линии RS в 1 (данные)
#define rs0 PORTB&=0b11111011 //установка линии RS в 0 (команда)
void ADC_ini();
float ADC_convert (void);
void send_half_byte(unsigned char c);
void send_byte(unsigned char c, unsigned char mode);
void send_char(unsigned char c);
void set_pos(unsigned char x, unsigned y);
void str_lcd (char str1[]);
void LCD_ini(void);
#endif /* MAIN_H_ */
Если есть вопросы и предложения по этому уроку, пишите комментарии буду рад ответить на ваши вопросы.
Часть 1
Часть 2-1 Часть 2-2
Часть 3-1 Часть 3-2
Часть 4-1 Часть 4-2
Мой блог в ЖЖ: http://evgenij-byvshev.livejournal.com