Страница 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);
  }
}
Дизасм строчки

Код: Выделить всё

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
Три команды.

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 писал(а):Ну вот... как же так ? Использовать и не знать во что разворачивается...
С каких это пор знание ассемблера обязательно для программирования на МК? :shock:

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 
Это пиз-ец

Код: Выделить всё

out   0x05, r24   ; 5                   
in   r24, 0x05   ; 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 заставляет человка заметно напрягать мозг, значит ему все еще необходимо учиться многим элементарным вещам. :wink:
Нереально допустить такое ошибки как 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);
Что тут напряжного ?
То, что можно по ошибке написать

Код: Выделить всё

CLR_BIT(DIN_PORT, RST_PIN);
и если порты у DIN и RST - разные, то потом долго чесать голову, почему у меня ничего не работает.

PS: И можно всё-таки пояснить зачем нужно знать ассемблер, чтобы программировать на МК?
HHIMERA писал(а): А что тут непонятного???
Во первых...
У многих МК не все пины толерантны к 5Вольтам... так что... не "привязываемся к пинам" - часто мнимое...
И как это относится к вопросу библиотеки C++ для работы с портами AVR?! :shock:

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 писал(а):С понятием "абстракция" знакомы??? :))
Да. Только при чём здесь это? Выражайте свою мысль яснее.