Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
evgenij-byvshev
7 лет назад

Программирование микроконтроллеров. Часть 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

19
462.073 GOLOS
На Golos с February 2017
Комментарии (1)
Сортировать по:
Сначала старые