Страница 1 из 3
Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 17:08:29
ArtDen
Недавно столкнулся с 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 17:24:21
blackx
Спасибо, надо будет попробовать. Правда не встречал тут пока никого, кто бы под АВР на плюсах писал...
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 17:44:24
ArtDen
blackx писал(а):Правда не встречал тут пока никого, кто бы под АВР на плюсах писал...
Ну так надо начинать. Не всё время же на ассемблере или на си возиться

Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 18:10:48
Аlex
Использовать библиотеку очень просто
А для чего она нужна ? Какое в ней преимущество перед обычными макросами сброса/установки/инверсии бита ?
PS: Можно посмотреть дизасм строки
LED1Pin::Cpl(); ?
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 18:27:29
ArtDen
Аlex писал(а):А для чего она нужна ? Какое в ней преимущество перед обычными макросами сброса/установки/инверсии бита ?
PS: Можно посмотреть дизасм строки LED1Pin::Cpl(); ?
Конкретно где получился LED1Pin не знаю, вот целиком дизассемблер программы, пример которой я показал:
Код: Выделить всё
sbi 0x04, 0 ; 4
cbi 0x05, 0 ; 5
sbi 0x04, 1 ; 4
sbi 0x05, 1 ; 5
ldi r22, 0x01 ; 1
ldi r23, 0x02 ; 2
ldi r20, 0xF4 ; 244
ldi r21, 0x01 ; 1
in r24, 0x05 ; 5
eor r24, r22
out 0x05, r24 ; 5
in r24, 0x05 ; 5
eor r24, r23
out 0x05, r24 ; 5
ldi r18, 0x88 ; 136
ldi r19, 0x13 ; 19
movw r24, r20
sbiw r24, 0x01 ; 1
brne .-4 ; 0x68 <main+0x22>
subi r18, 0x01 ; 1
sbci r19, 0x00 ; 0
brne .-12 ; 0x66 <main+0x20>
rjmp .-30 ; 0x56 <main+0x10>
А нужна она вот для чего. Допустим, я делаю библиотеку (в виде класса) для работы с 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();
...
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 18:36:05
YS
А нужна она вот для чего. Допустим, я делаю библиотеку (в виде класса) для работы с LCD-экраном нокии. Мне нужно чтобы она не была привязана к конкретным ногам МК.
А дефайны - уже не модно?
Код: Выделить всё
#define PORT PORTA
#define RST_PINMASK 0x01
#define E_PINMASK 0x04
...
PORT|=RST_PINMASK;
...
PORT&=~E_PINMASK;
Как по мне, не надо насильно пихать ООП туда, где оно не нужно.

Это приводит как минимум к лишнему мельтешению букв.
Код: Выделить всё
RST_Pin::ConfOut();
CE_Pin::ConfOut();
DC_Pin::ConfOut();
DIN_Pin::ConfOut();
CLK_Pin::ConfOut();
С дефайнами будет в одну строку.
Код: Выделить всё
PORT|=RST_PIN | CE_PIN | DC_PIN | DIN_PIN | CLK_PIN;
И уложится компилятором в гораздо более компактный код. Скорее всего, в две инструкции - загрузку константы (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
pure C:
Код: Выделить всё
#include <avr/io.h>
#include <util/delay.h>
#define LED_PORT PORTB
#define LED_DDR DDRB
#define LED1_PIN (0x01)
#define LED2_PIN (0x02)
void main(void)
{
LED_DDR=LED1_PIN | LED2_PIN;
LED_PORT=0;
while (1)
{
LED_PORT^=(LED1_PIN | LED2_PIN);
_delay_ms(500);
}
}
Дизасм строчки
Код: Выделить всё
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
Три команды.
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:00:29
ArtDen
YS писал(а):А дефайны - уже не модно?
Да я не заставляю на эту либу всех переходить. Кому нравиться - он и на ассемблере пишет

Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:07:36
YS
Кому нравиться - он и на ассемблере пишет
Дыг а для тех, для кого ассемблер - пища зело твердая, есть Ардуино с Вайрингом.

Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:11:47
HHIMERA
ArtDen писал(а):
Конкретно где получился LED1Pin не знаю, вот целиком дизассемблер программы,
Хорошее начало...
Недавно столкнулся с C++ - библиотекой для работы с портами ввода/вывода на STM32. Очень удобная штука.
Хм...
А нужна она вот для чего. Допустим, я делаю библиотеку (в виде класса) для работы с LCD-экраном нокии. Мне нужно чтобы она не была привязана к конкретным ногам МК.
Зашибись... берём STM32, вяжем к нему 5-ти вольтовый 16х2 как попало, а потом удивляемся...
Или... привязываем как причудилось к новым PIC'ам и кричим "ПИК гавно, генератор не запускается, ADC глючит"...

Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:17:33
ArtDen
HHIMERA, не понял твою мысль
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:18:59
Аlex
Мне нужно чтобы она не была привязана к конкретным ногам МК
Это я уже понял. А преимущество перед дефайнами то в чём ?
Конкретно где получился LED1Pin не знаю
Ну вот... как же так ? Использовать и не знать во что разворачивается...
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:27:40
ArtDen
Аlex писал(а):Это я уже понял. А преимущество перед дефайнами то в чём ?
В том, что
1. Код проще читается. Не надо напрягать мозги при виде
RST_PORT &= ~RST_PINMASK;. Выражение
RST_Pin::Off(); гораздо понятнее.
2. Нереально допустить такое ошибки как
RST_PORT &= RST_PINMASK;
Аlex писал(а):Ну вот... как же так ? Использовать и не знать во что разворачивается...
С каких это пор знание ассемблера обязательно для программирования на МК?

Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:30:12
ILYAUL
Конкретно где получился LED1Pin не знаю
Bot
Код: Выделить всё
in r24, 0x05 ; 5
eor r24, r22
out 0x05, r24 ; 5
in r24, 0x05 ; 5
eor r24, r23
out 0x05, r24 ; 5
Это пиз-ец
С каких это пор знание ассемблера обязательно для программирования на МК?
Что бы всегда можно было написать
Это пиз-ец
Да!И не писать вот это
Конкретно где получился LED1Pin не знаю
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:50:09
YS
Код проще читается. Не надо напрягать мозги при виде 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."
http://en.wikipedia.org/wiki/Wiring_(de ... _platform)
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:52:52
Аlex
В том, что
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);
Что тут напряжного ?
С каких это пор знание ассемблера обязательно для программирования на МК?
С тех пор, когда Вы начали их изучать.
ЗЫ: Опередили меня

Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 19:54:57
HHIMERA
ArtDen писал(а):HHIMERA, не понял твою мысль
А что тут непонятного???
Во первых...
У многих МК не все пины толерантны к 5Вольтам... так что... не "привязываемся к пинам" - часто мнимое...
Во вторых...
Если дисплей, тот же, от Нокии, вешать по человечески на SPI, то вариантов - раз-два... и всё...
В общем... мысль, что можно совать что попало и куда попало "не привязываясь", у некоторых (у новичков в частности) вызывает ассоциации и призывы к прямому действию... что чревато... Ну вот как-то так...
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 20:03:07
ArtDen
Аlex писал(а):CLR_BIT(RST_PORT, RST_PIN);
Что тут напряжного ?
То, что можно по ошибке написать
и если порты у DIN и RST - разные, то потом долго чесать голову, почему у меня ничего не работает.
PS: И можно всё-таки пояснить зачем нужно знать ассемблер, чтобы программировать на МК?
HHIMERA писал(а):
А что тут непонятного???
Во первых...
У многих МК не все пины толерантны к 5Вольтам... так что... не "привязываемся к пинам" - часто мнимое...
И как это относится к вопросу библиотеки C++ для работы с портами AVR?!

Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 20:04:01
Аlex
я делаю библиотеку (в виде класса) для работы с LCD-экраном нокии
С вашей библиотекой Вы будете ждать прорисовку экрана до бесконечности, тем более на низкоскоростных МК.
То, что можно по ошибке написать
как можно по ошибке написать ненужное ? С таким подходм вообще не стоит садиться за программирование, т.к. по ошибке можно место
if написать
for
PS: И можно всё-таки пояснить зачем нужно знать ассемблер, чтобы программировать на МК?
Что-бы потом не задавать глупых вопросов, типа "почему у меня это делается медленно, я же всего лишь одну строчку написал ?"....
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 20:11:06
HHIMERA
ArtDen писал(а):
1. Код проще читается. Не надо напрягать мозги при виде RST_PORT &= ~RST_PINMASK;. Выражение RST_Pin::Off(); гораздо понятнее.
С понятием "абстракция" знакомы???
2. Нереально допустить такое ошибки как RST_PORT &= RST_PINMASK;
Не бывает нереальных ошибок... все они реальные...
Re: Пример работы с I/O портами AVR на C++
Добавлено: Сб фев 02, 2013 20:13:49
ArtDen
HHIMERA писал(а):С понятием "абстракция" знакомы???
Да. Только при чём здесь это? Выражайте свою мысль яснее.