Недавно столкнулся с C++ - библиотекой для работы с портами ввода/вывода на STM32. Очень удобная штука. Упрощает кучу вещей за счёт того позволяет определить вывод порта в одном месте программы. Был удивлён, что такой до сих пор нету для AVR-ок и по быстрому набросал вот такой код: http://muil.googlecode.com/svn/trunk/mcu/avr8/pin.hpp Использовать библиотеку очень просто. Вот пример моргания двумя светодиодами:
Код:
#include <avr/io.h> #include <util/delay.h>
#include "pin.hpp" // подключаем библиотеку
typedef Pin<'B', 0> LED1Pin; // определяем ногу для первого светодиода. Порт B, 0-я нога typedef Pin<'B', 1> LED2Pin; // определяем ногу для второго светодиода. Порт B, 1-я нога
int main() { // Настраиваем ногу для первого светодиода LED1Pin::ConfOut(); // Нога работает на выход LED1Pin::Off(); // Нога выключена
// Настраиваем ногу для второго светодиода LED2Pin::ConfOut(); // Нога работает на выход LED2Pin::On(); // Нога включена
// Мигаем светодиодами for (;;) { LED1Pin::Cpl(); // Инвертируем состояние ноги первого светодиода LED2Pin::Cpl(); // Инвертируем состояние ноги второго светодиода _delay_ms(500); // Делаем задержку } }
Библиотека работает под WinAVR. В других компиляторах не тестировал. Может кому пригодится.
Заголовок сообщения: Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 18:10:48
Модератор
Карма: 90
Рейтинг сообщений: 1341
Зарегистрирован: Чт мар 18, 2010 23:09:57 Сообщений: 4561 Откуда: Планета Земля
Рейтинг сообщения:0 Медали: 1
Цитата:
Использовать библиотеку очень просто
А для чего она нужна ? Какое в ней преимущество перед обычными макросами сброса/установки/инверсии бита ? PS: Можно посмотреть дизасм строки LED1Pin::Cpl(); ?
Компания MEAN WELL пополнила ассортимент своей широкой линейки светодиодных драйверов новым семейством XLC для внутреннего освещения. Главное отличие – поддержка широкого спектра проводных и беспроводных технологий диммирования. Новинки представлены в MEANWELL.market моделями с мощностями 25 Вт, 40 Вт и 60 Вт. В линейке есть модели, работающие как в режиме стабилизации тока (СС), так и в режиме стабилизации напряжения (CV) значением 12, 24 и 48 В.
А для чего она нужна ? Какое в ней преимущество перед обычными макросами сброса/установки/инверсии бита ? PS: Можно посмотреть дизасм строки LED1Pin::Cpl(); ?
Конкретно где получился LED1Pin не знаю, вот целиком дизассемблер программы, пример которой я показал:
А нужна она вот для чего. Допустим, я делаю библиотеку (в виде класса) для работы с LCD-экраном нокии. Мне нужно чтобы она не была привязана к конкретным ногам МК. В этом случае я поступаю так:
Код:
template <typename RST_Pin, typename CE_Pin, typename DC_Pin, typename DIN_Pin, typename CLK_Pin> class NOKIA5110LCD { public: ... // далее идут внутренности класса
А затем использую этот класс вот так:
Код:
// Определяем пины, которые будут использоваться для работы с LCD-экраном: typedef Pin<'A', 0> RST_Pin; typedef Pin<'A', 1> CE_Pin; typedef Pin<'A', 2> DC_Pin; typedef Pin<'A', 3> DIN_Pin; typedef Pin<'A', 4> CLK_Pin; // Определяем LCD: typedef NOKIA5110LCD<RST_Pin, CE_Pin, DC_Pin, DIN_Pin, CLK_Pin> LCD; // Настраиваем пины: RST_Pin::ConfOut(); CE_Pin::ConfOut(); DC_Pin::ConfOut(); DIN_Pin::ConfOut(); CLK_Pin::ConfOut(); // Работаем с LCD LCD::init(); ...
А нужна она вот для чего. Допустим, я делаю библиотеку (в виде класса) для работы с LCD-экраном нокии. Мне нужно чтобы она не была привязана к конкретным ногам МК.
А дефайны - уже не модно?
Код:
#define PORT PORTA #define RST_PINMASK 0x01 #define E_PINMASK 0x04
...
PORT|=RST_PINMASK; ... PORT&=~E_PINMASK;
Как по мне, не надо насильно пихать ООП туда, где оно не нужно. Это приводит как минимум к лишнему мельтешению букв.
И уложится компилятором в гораздо более компактный код. Скорее всего, в две инструкции - загрузку константы (RST_PIN | CE_PIN | DC_PIN | DIN_PIN | CLK_PIN) и ее вывод в DDRn.
UPD: Переписал программу из первого поста на pure C.
Исходно:
Код:
#include <avr/io.h> #include <util/delay.h>
#include "pin.hpp" // подключаем библиотеку
typedef Pin<'B', 0> LED1Pin; // определяем ногу для первого светодиода. Порт B, 0-я нога typedef Pin<'B', 1> LED2Pin; // определяем ногу для второго светодиода. Порт B, 1-я нога
int main() { // Настраиваем ногу для первого светодиода LED1Pin::ConfOut(); // Нога работает на выход LED1Pin::Off(); // Нога выключена
// Настраиваем ногу для второго светодиода LED2Pin::ConfOut(); // Нога работает на выход LED2Pin::On(); // Нога включена
// Мигаем светодиодами for (;;) { LED1Pin::Cpl(); // Инвертируем состояние ноги первого светодиода LED2Pin::Cpl(); // Инвертируем состояние ноги второго светодиода _delay_ms(500); // Делаем задержку } }
Дизасм строчек
Код:
LED1Pin::Cpl(); // Инвертируем состояние ноги первого светодиода LED2Pin::Cpl(); // Инвертируем состояние ноги второго светодиода
Код:
in r24, 0x05 ; 5 eor r24, r22 out 0x05, r24 ; 5 in r24, 0x05 ; 5 eor r24, r23 out 0x05, r24 ; 5
while (1) { LED_PORT^=(LED1_PIN | LED2_PIN); _delay_ms(500); } }
Дизасм строчки
Код:
LED_PORT^=(LED1_PIN | LED2_PIN);
Код:
16: LED_PORT^=(LED1_PIN | LED2_PIN); +00000029: B185 IN R24,0x05 In from I/O location +0000002A: 2784 EOR R24,R20 Exclusive OR +0000002B: B985 OUT 0x05,R24 Out to I/O location
Три команды.
_________________ Разница между теорией и практикой на практике гораздо больше, чем в теории.
Конкретно где получился LED1Pin не знаю, вот целиком дизассемблер программы,
Хорошее начало...
Цитата:
Недавно столкнулся с C++ - библиотекой для работы с портами ввода/вывода на STM32. Очень удобная штука.
Хм...
Цитата:
А нужна она вот для чего. Допустим, я делаю библиотеку (в виде класса) для работы с LCD-экраном нокии. Мне нужно чтобы она не была привязана к конкретным ногам МК.
Зашибись... берём STM32, вяжем к нему 5-ти вольтовый 16х2 как попало, а потом удивляемся... Или... привязываем как причудилось к новым PIC'ам и кричим "ПИК гавно, генератор не запускается, ADC глючит"...
_________________ "Я не даю готовых решений, я заставляю думать!"(С)
Это я уже понял. А преимущество перед дефайнами то в чём ?
В том, что 1. Код проще читается. Не надо напрягать мозги при виде RST_PORT &= ~RST_PINMASK;. Выражение RST_Pin::Off(); гораздо понятнее. 2. Нереально допустить такое ошибки как RST_PORT &= RST_PINMASK;
Аlex писал(а):
Ну вот... как же так ? Использовать и не знать во что разворачивается...
С каких это пор знание ассемблера обязательно для программирования на МК?
Код проще читается. Не надо напрягать мозги при виде RST_PORT &= ~RST_PINMASK;. Выражение RST_Pin::Off(); гораздо понятнее.
Спорно. Когда таких записей штук пять-восемь, от XXX_Pin::SomeMethod() начинает рябить в глазах. В то время как настройка одного порта логическими операциями записывается в одну-две строчки в любом случае.
Кроме того, для каждой такой ООП-шной строчки, как выясняется, компилятор генерирует отдельный набор команд доступа к порту, что раздувает программу.
Вообще, если запись some_var&=~SOME_DEFINE заставляет человка заметно напрягать мозг, значит ему все еще необходимо учиться многим элементарным вещам.
Цитата:
Нереально допустить такое ошибки как RST_PORT &= RST_PINMASK;
Можно сделать макрос
Код:
#define MASK_CLEAR(PORT, MASK) ((PORT)&=~(MASK))
Цитата:
С каких это пор знание ассемблера обязательно для программирования на МК?
С тех самых пор, как их изобрели. Вообще, даже занимаясь программированием x86 очень полезно знать ассемблер. А для ма-а-а-аленьких контроллеров типа AVR это просто обязательно. Нормальное обучение программированию контроллеров должно начинаться с ассемблера.
Все сказанное справедливо, конечно, только для случая, когда человек и правда хочет что-то понимать и быть компетентным в предметной области. Для дилетантов всегда есть Ардуино.
"Wiring and Processing have spawned another project, Arduino, which uses the Processing IDE, with a simplified version of the C++ language, as a way to teach artists and designers how to program microcontrollers."
Заголовок сообщения: Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:52:52
Модератор
Карма: 90
Рейтинг сообщений: 1341
Зарегистрирован: Чт мар 18, 2010 23:09:57 Сообщений: 4561 Откуда: Планета Земля
Рейтинг сообщения:0 Медали: 1
Цитата:
В том, что 1. Код проще читается. Не надо напрягать мозги при виде RST_PORT &= ~RST_PINMASK;. Выражение RST_Pin::Off(); гораздо понятнее. 2. Нереально допустить такое ошибки как RST_PORT &= RST_PINMASK;
Код:
#define CLR_BIT(p, b) p&=~(1<<b)
#define RST_PORT PORTA #define RST_PIN 1
......... .........
CLR_BIT(RST_PORT, RST_PIN);
Что тут напряжного ?
Цитата:
С каких это пор знание ассемблера обязательно для программирования на МК?
А что тут непонятного??? Во первых... У многих МК не все пины толерантны к 5Вольтам... так что... не "привязываемся к пинам" - часто мнимое... Во вторых... Если дисплей, тот же, от Нокии, вешать по человечески на SPI, то вариантов - раз-два... и всё... В общем... мысль, что можно совать что попало и куда попало "не привязываясь", у некоторых (у новичков в частности) вызывает ассоциации и призывы к прямому действию... что чревато... Ну вот как-то так...
_________________ "Я не даю готовых решений, я заставляю думать!"(С)
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 18
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения