больше веселья с C ++, шаблонами и GPIO

Рик Кимбалл
Вт, 09 июня, 2015, 8:44 вечера
Я взял код GPIO, который я опубликовал в другом потоке на следующий уровень. Этот обеспечивает абстракцию PIN -код и некоторые изящные методы доступа. // more fun with c++ classes and templates class GPIOPort : public gpio_reg_map { public: void high(const uint32_t pin) { BSRR = 1 << pin; } void low(const uint32_t pin) { BRR = 1 << pin; } void pinMode(const uint32_t pin, gpio_pin_mode mode) { volatile uint32_t *cr = &CRL + (pin >> 3); uint32_t shift = (pin & 0x7) * 4; uint32_t tmp = *cr; tmp &= ~(0xF << shift); tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; *cr = tmp; if (mode == GPIO_INPUT_PD) { ODR &= ~(1u << pin); } else if (mode == GPIO_INPUT_PU) { ODR |= (1u << pin); } } int value(const uint32_t pin) { return (IDR & (1u<< pin) ? 1 : 0); } }; #define GPIOPORT_REF(a) *((GPIOPort * const)(a)) static GPIOPort & gPortA = GPIOPORT_REF(0x40010800); static GPIOPort & gPortB = GPIOPORT_REF(0x40010C00); static GPIOPort & gPortC = GPIOPORT_REF(0x40011000); template class GPIOPortBPin { public: void high() { gPortB.high(PIN); } void low() { gPortB.low(PIN); } void operator=(const int value) { if ( value ) gPortB.high(PIN); else gPortB.low(PIN); } operator int() { return gPortB.value(PIN); } void pinMode(WiringPinMode mode) { gpio_pin_mode gpio_mode; bool pwm = false; switch(mode) { case OUTPUT: gpio_mode = GPIO_OUTPUT_PP; break; case OUTPUT_OPEN_DRAIN: gpio_mode = GPIO_OUTPUT_OD; break; case INPUT: case INPUT_FLOATING: gpio_mode = GPIO_INPUT_FLOATING; break; case INPUT_ANALOG: gpio_mode = GPIO_INPUT_ANALOG; break; case INPUT_PULLUP: gpio_mode = GPIO_INPUT_PU; break; case INPUT_PULLDOWN: gpio_mode = GPIO_INPUT_PD; break; case PWM: gpio_mode = GPIO_AF_OUTPUT_PP; pwm = true; break; case PWM_OPEN_DRAIN: gpio_mode = GPIO_AF_OUTPUT_OD; pwm = true; break; default: return; } gPortB.pinMode(PIN, gpio_mode); (void)pwm; // TODO: implement timer start/stop } }; typedef GPIOPortBPin<1> PB_1; typedef GPIOPortBPin<2> PB_2; // ... and on and on typedef GPIOPortBPin<11> PB_15; PB_1 LED1; #define fastWrite(pin,value) do { (value) ? pin.high() : pin.low(); } while(0) // void setup() { LED1.pinMode(OUTPUT); } void loop() { LED1 = 1; delay(50); LED1 = 0; delay(250); LED1.high(); delay(50); LED1.low(); delay(450); fastWrite(LED1,1); delay(50); fastWrite(LED1,0); delay(450); }

Mrburnette
Ср 10 июня 2015 г. 12:23
Отличная работа!

Луча

Ахулл
Ср 10 июня 2015 г. 12:54
Конечно, цикл довольно аккуратный, я полагаю, что все размер кода одинаково лаконично.

Рик Кимбалл
Ср 10 июня 2015 г. 1:05
К сожалению, нет @ahull. Я все еще привязан к этой барже то, что мы называем Libmaple; )

Porellan63
Пт 12 июня 2015 г., 17:40
Рик
Здравствуйте, я видел ваш пример кода "C ++, шаблоны GPIO", и я пытаюсь восстановить его в Arduino и в Maple, но я еще не смог
В Ардуино 1.6.4 IDE висел в прогрессивной панели, пытаясь скомпилировать его, и в Maple дал сообщение об ошибке
«Ошибка: ожидаемое класс-имени до '{' token in member function 'void gpioport :: high (int)':"
Я не эксперт, поэтому, если вы хотите помочь, не могли бы вы это сделать ?
У меня есть доска олимексино
любая помощь, которую это может быть оценено
С наилучшими пожеланиями
Пабло
Электроника

Рик Кимбалл
Пт 12 июня 2015 г. 18:23
Porellan63 написал:У меня есть доска олимексино
любая помощь, которую это может быть оценено
С наилучшими пожеланиями
Пабло
Электроника

Рик Кимбалл
Пт 12 июня 2015 г. 18:29
Хорошо, я только что сделал натягивание на GitHub https: // github.com/rogerclarkmelbourne/arduino_stm32, Итак, теперь я синхронизируюсь с последними. И эскиз компилируется и, кажется, работает нормально.

Я использую компилятор и Arduino 1.6.5 построено из источника из GitHub. (Арудино.CC Master Branch) на Linux с платой Maple Mini Clone, запрограммированной через программист Stlink-V2.

-рик

Рик Кимбалл
Пт 12 июня 2015 г., 18:35
Извините, я не использую выбор Maple-Mini. У меня есть общий F103CB с STLINK One Ficked. Я использую Maple Mini Board, но без загрузки DFU.

-рик

Porellan63
Пт 12 июня 2015 г., 19:44
Рик
Я проверил ваш код в моей доске Olimexino, и он работает идеально// more fun with c++ classes and templates class GPIOPort : public gpio_reg_map { public: void high(const uint32_t pin) { BSRR = 1 << pin; } void low(const uint32_t pin) { BRR = 1 << pin; } void pinMode(const uint32_t pin, gpio_pin_mode mode) { volatile uint32_t *cr = &CRL + (pin >> 3); uint32_t shift = (pin & 0x7) * 4; uint32_t tmp = *cr; tmp &= ~(0xF << shift); tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; *cr = tmp; if (mode == GPIO_INPUT_PD) { ODR &= ~(1u << pin); } else if (mode == GPIO_INPUT_PU) { ODR |= (1u << pin); } } int value(const uint32_t pin) { return (IDR & (1u<< pin) ? 1 : 0); } }; #define GPIOPORT_REF(a) *((GPIOPort * const)(a)) static GPIOPort & gPortA = GPIOPORT_REF(0x40010800); static GPIOPort & gPortB = GPIOPORT_REF(0x40010C00); static GPIOPort & gPortC = GPIOPORT_REF(0x40011000); template class GPIOPortBPin { public: void high() { gPortB.high(PIN); } void low() { gPortB.low(PIN); } void operator=(const int value) { if ( value ) gPortB.high(PIN); else gPortB.low(PIN); } operator int() { return gPortB.value(PIN); } void pinMode(WiringPinMode mode) { gpio_pin_mode gpio_mode; bool pwm = false; switch(mode) { case OUTPUT: gpio_mode = GPIO_OUTPUT_PP; break; case OUTPUT_OPEN_DRAIN: gpio_mode = GPIO_OUTPUT_OD; break; case INPUT: case INPUT_FLOATING: gpio_mode = GPIO_INPUT_FLOATING; break; case INPUT_ANALOG: gpio_mode = GPIO_INPUT_ANALOG; break; case INPUT_PULLUP: gpio_mode = GPIO_INPUT_PU; break; case INPUT_PULLDOWN: gpio_mode = GPIO_INPUT_PD; break; case PWM: gpio_mode = GPIO_AF_OUTPUT_PP; pwm = true; break; case PWM_OPEN_DRAIN: gpio_mode = GPIO_AF_OUTPUT_OD; pwm = true; break; default: return; } gPortB.pinMode(PIN, gpio_mode); (void)pwm; // TODO: implement timer start/stop } }; template class GPIOPortAPin { public: void high() { gPortA.high(PIN); } void low() { gPortA.low(PIN); } void operator=(const int value) { if ( value ) gPortA.high(PIN); else gPortA.low(PIN); } operator int() { return gPortA.value(PIN); } void pinMode(WiringPinMode mode) { gpio_pin_mode gpio_mode; bool pwm = false; switch(mode) { case OUTPUT: gpio_mode = GPIO_OUTPUT_PP; break; case OUTPUT_OPEN_DRAIN: gpio_mode = GPIO_OUTPUT_OD; break; case INPUT: case INPUT_FLOATING: gpio_mode = GPIO_INPUT_FLOATING; break; case INPUT_ANALOG: gpio_mode = GPIO_INPUT_ANALOG; break; case INPUT_PULLUP: gpio_mode = GPIO_INPUT_PU; break; case INPUT_PULLDOWN: gpio_mode = GPIO_INPUT_PD; break; case PWM: gpio_mode = GPIO_AF_OUTPUT_PP; pwm = true; break; case PWM_OPEN_DRAIN: gpio_mode = GPIO_AF_OUTPUT_OD; pwm = true; break; default: return; } gPortA.pinMode(PIN, gpio_mode); (void)pwm; // TODO: implement timer start/stop } }; typedef GPIOPortAPin<1> PA_1; typedef GPIOPortAPin<2> PA_2; typedef GPIOPortAPin<3> PA_3; typedef GPIOPortAPin<4> PA_4; typedef GPIOPortAPin<5> PA_5; // ... and on and on typedef GPIOPortAPin<15> PA_15; typedef GPIOPortBPin<1> PB_1; typedef GPIOPortBPin<2> PB_2; // ... and on and on typedef GPIOPortBPin<11> PB_15; PA_1 LED2; PA_5 LED1; #define fastWrite(pin,value) do { (value) ? pin.high() : pin.low(); } while(0) // void setup() { LED1.pinMode(OUTPUT); LED2.pinMode(OUTPUT); } void loop() { LED1 = 1; LED2 = 1; delay(200); LED1 = 0; LED2 = 0; delay(200); LED1.high(); LED2.high(); delay(200); LED1.low(); LED2.low(); delay(200); //fastWrite(LED1,1); //delay(50); //fastWrite(LED1,0); //delay(450); }

ZMEMW16
Сб 8 августа 2015 11:42
Я пытаюсь использовать ваш код для управления SSD1306 SPI 0.96 "OLED

У меня был стандартный пример «использование SPI», который работал, и удивлялся, почему форма волны CS казалась слишком долго до начала SCLK, а также после остановков SCLK.

видеть http: // www.STM32duino.com/viewtopic.PHP?f = 9&t = 481

Victor_py предложил посмотреть на ваш пост.

Я использую плату Zet6, поэтому у меня есть порты A-G, теперь адреса, я думаю, потому что я не могу найти информацию о картировании.
Так что, поскольку интервал кажется 0x400, я только что играл :-)
static GPIOPort & gPortA = GPIOPORT_REF(0x40010800); static GPIOPort & gPortB = GPIOPORT_REF(0x40010C00); static GPIOPort & gPortC = GPIOPORT_REF(0x40011000);

Рик Кимбалл
Солнце 09 августа 2015, 16:07
ZMEMW16 написал:Возможно ли написать это, чтобы его можно было использовать для любого порта, например, а, b, ... G и т.д ?
Любые указатели на полезную документацию были бы хорошими, я нашел это из инструментов разработки Hitex

ZMEMW16
Солнце 09 августа 2015 г., 16:41
Еще одна ссылка DOC
Google с «обнаружением микроконтроллера STM32 Джеффри Браун»

довольно содержание курса и просто сканирование - упражнение 4.3 выглядит довольно полезно!

Стивен

victor_pv
Пт 30 июня 2017 г. 12:52
Рик, воскресший эту ветку для вопроса.

Что произойдет, если бы я использовал PB1 против PB_1?
Такой как: typedef gpioportbpin<1> PB1; Даст ли это ошибку, потому что PB1 уже определяется где -то как что -то другое?

Рик Кимбалл
Пт 30 июня 2017 г. 12:17
Да, это потерпит неудачу. PB2 уже используется как перечисление.
sketch_jun30a:100: error: 'typedef class GPIOPortBPin<2ul> PB2' redeclared as different kind of symbol typedef GPIOPortBPin<2> PB2; ^~~ In file included from /home/kimballr/Arduino/hardware/arduino_stm32/STM32F1/cores/maple/boards.h:39:0, from /home/kimballr/Arduino/hardware/arduino_stm32/STM32F1/cores/maple/wirish.h:54, from /home/kimballr/Arduino/hardware/arduino_stm32/STM32F1/cores/maple/Arduino.h:30, from /tmp/arduino_build_107833/sketch/sketch_jun30a.ino.cpp:1: /home/kimballr/Arduino/hardware/arduino_stm32/STM32F1/variants/generic_stm32f103c/board/board.h:81:12: note: previous declaration ' PB2' PB0, PB1, PB2, PB3, PB4, PB5, PB6, PB7, PB8, PB9, PB10, PB11, PB12, PB13,PB14,PB15, ^~~ exit status 1 'typedef class GPIOPortBPin<2ul> PB2' redeclared as different kind of symbol

Рик Кимбалл
Сб 16 сентября 2017 г. 18:03
[ZMEMW16 - Сб 8 августа 2015 г., 23:42] - Возможно ли написать это, чтобы его можно было использовать для любого порта, например, а, b, ... G и т.д ?
@zmemw16 Я по какой -то причине смотрел на это снова. Я сделал простое изменение, которое позволяет вам делать то, что вы хотите.

Я добавил функцию члена общего шаблона с именем gpioportx (), которая возвращает правильный порт на основе числа. Вы должны использовать другой синтаксис для шаблона PIN. Все еще так же эффективен, просто более гибкий.

typedef gpioportpin<1, 0> PA_0; // где 1 порта и 0 - булавка 0 ...
...
typedef gpioportpin<2, 0> PB_0; // где 2 - порт, а 0 - булавка 0
...
typedef gpioportpin<3, 13> PC_13; // где 3 - это порт, а 13 - булавка 13 (светодиод синей таблетки)
...
typedef gpioportpin<7, 0> PG_13; // где 7 - порт, а 0 - булавка 0

Вот измененный код: или захватить отсюда GitHub take2.Ино // more fun with c++ classes and templates // http://www.stm32duino.com/viewtopic.php?f=18&t=303 class GPIOPort : public gpio_reg_map { public: void high(const uint32_t pin) { BSRR = 1 << pin; } void low(const uint32_t pin) { BRR = 1 << pin; } void pinMode(const uint32_t pin, gpio_pin_mode mode) { volatile uint32_t *cr = &CRL + (pin >> 3); uint32_t shift = (pin & 0x7) * 4; uint32_t tmp = *cr; tmp &= ~(0xF << shift); tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; *cr = tmp; if (mode == GPIO_INPUT_PD) { ODR &= ~(1u << pin); } else if (mode == GPIO_INPUT_PU) { ODR |= (1u << pin); } } int value(const uint32_t pin) { return (IDR & (1u << pin) ? 1 : 0); } }; #define GPIOPORT_REF(a) *((GPIOPort * const)(a)) template class GPIOPortPin { public: GPIOPort & GPIOPortX() { switch (PORT) { case 1: return GPIOPORT_REF(0x40010800); break; // GPIOA case 2: return GPIOPORT_REF(0x40010C00); break; // GPIOB case 3: return GPIOPORT_REF(0x40011000); break; // GPIOC case 4: return GPIOPORT_REF(0x40011400); break; // GPIOD case 5: return GPIOPORT_REF(0x40011800); break; // GPIOE case 6: return GPIOPORT_REF(0x40011C00); break; // GPIOF case 7: return GPIOPORT_REF(0x40012000); break; // GPIOG default: return GPIOPORT_REF(0x40010800); break; // ignore error, default to A } } void high() { GPIOPortX().high(PIN); } void low() { GPIOPortX().low(PIN); } // set using operator overload void operator=(const int value) { if ( value ) GPIOPortX().high(PIN); else GPIOPortX().low(PIN); } // get using operator overload operator int() { return GPIOPortX().value(PIN); } void pinMode(WiringPinMode mode) { gpio_pin_mode gpio_mode; bool pwm = false; switch (mode) { case OUTPUT: gpio_mode = GPIO_OUTPUT_PP; break; case OUTPUT_OPEN_DRAIN: gpio_mode = GPIO_OUTPUT_OD; break; case INPUT: case INPUT_FLOATING: gpio_mode = GPIO_INPUT_FLOATING; break; case INPUT_ANALOG: gpio_mode = GPIO_INPUT_ANALOG; break; case INPUT_PULLUP: gpio_mode = GPIO_INPUT_PU; break; case INPUT_PULLDOWN: gpio_mode = GPIO_INPUT_PD; break; case PWM: gpio_mode = GPIO_AF_OUTPUT_PP; pwm = true; break; case PWM_OPEN_DRAIN: gpio_mode = GPIO_AF_OUTPUT_OD; pwm = true; break; default: return; } GPIOPortX().pinMode(PIN, gpio_mode); (void)pwm; // TODO: implement timer start/stop } }; #define fastWrite(pin,value) do { (value) ? pin.high() : pin.low(); } while(0) typedef GPIOPortPin<1, 0> PA_0; typedef GPIOPortPin<1, 1> PA_1; // ... and on and on typedef GPIOPortPin<1, 15> PA_15; typedef GPIOPortPin<2, 0> PB_0; typedef GPIOPortPin<2, 1> PB_1; typedef GPIOPortPin<2, 2> PB_2; // ... and on and on typedef GPIOPortPin<2, 15> PB_15; typedef GPIOPortPin<3, 13> PC_13; typedef GPIOPortPin<3, 14> PC_14; typedef GPIOPortPin<3, 15> PC_15; PC_13 LED1; // blue pill led void setup() { LED1.pinMode(OUTPUT); } void loop() { #if 1 // set using operator= LED1 = LOW; delay(50); // set using operator=, get using operator int LED1 = !LED1; delay(250); #endif #if 1 int v = 0; // set using operator= LED1 = v++; delay(50); LED1 = v--; delay(250); #endif #if 1 // set using operator= LED1 = LOW; delay(50); LED1 = HIGH; delay(250); #endif #if 1 // set using member function call LED1.low(); delay(50); LED1.high(); delay(250); #endif #if 1 // set using a macro calling member function fastWrite(LED1, 0); delay(50); fastWrite(LED1, 1); delay(950); #endif }

Ристоматти
Сб, 16 июня 2018 г., 22:42
Отличная работа! Мне нравились библиотеки Digitalio / Directio для классических досок Arduino, так что приятно иметь аналогичный синтаксис также для STM32. Я предпочитаю использовать шаблоны, непосредственно давая описательное имя без обширного списка Typedef. Поэтому я завернул ваш код в файл gpioportpin.h и добавил перечисление для названий портов и пропустил пример Typedefs:
// more fun with c++ classes and templates // http://www.stm32duino.com/viewtopic.php?f=18&t=303 class GPIOPort : public gpio_reg_map { public: void high(const uint32_t pin) { BSRR = 1 << pin; } void low(const uint32_t pin) { BRR = 1 << pin; } void pinMode(const uint32_t pin, gpio_pin_mode mode) { volatile uint32_t *cr = &CRL + (pin >> 3); uint32_t shift = (pin & 0x7) * 4; uint32_t tmp = *cr; tmp &= ~(0xF << shift); tmp |= (mode == GPIO_INPUT_PU ? GPIO_INPUT_PD : mode) << shift; *cr = tmp; if (mode == GPIO_INPUT_PD) { ODR &= ~(1u << pin); } else if (mode == GPIO_INPUT_PU) { ODR |= (1u << pin); } } int value(const uint32_t pin) { return (IDR & (1u << pin) ? 1 : 0); } }; #define GPIOPORT_REF(a) *((GPIOPort * const)(a)) typedef enum GPIOPortName { PORT_A = 1, PORT_B = 2, PORT_C = 3, PORT_D = 4, PORT_E = 5, PORT_F = 6, PORT_G = 7 } GPIOPortName; template class GPIOPortPin { public: GPIOPort & GPIOPortX() { switch (PORT) { case PORT_A: return GPIOPORT_REF(0x40010800); break; // GPIOA case PORT_B: return GPIOPORT_REF(0x40010C00); break; // GPIOB case PORT_C: return GPIOPORT_REF(0x40011000); break; // GPIOC case PORT_D: return GPIOPORT_REF(0x40011400); break; // GPIOD case PORT_E: return GPIOPORT_REF(0x40011800); break; // GPIOE case PORT_F: return GPIOPORT_REF(0x40011C00); break; // GPIOF case PORT_G: return GPIOPORT_REF(0x40012000); break; // GPIOG default: return GPIOPORT_REF(0x40010800); break; // ignore error, default to A } } void high() { GPIOPortX().high(PIN); } void low() { GPIOPortX().low(PIN); } // set using operator overload void operator=(const int value) { if ( value ) GPIOPortX().high(PIN); else GPIOPortX().low(PIN); } // get using operator overload operator int() { return GPIOPortX().value(PIN); } void pinMode(WiringPinMode mode) { gpio_pin_mode gpio_mode; bool pwm = false; switch (mode) { case OUTPUT: gpio_mode = GPIO_OUTPUT_PP; break; case OUTPUT_OPEN_DRAIN: gpio_mode = GPIO_OUTPUT_OD; break; case INPUT: case INPUT_FLOATING: gpio_mode = GPIO_INPUT_FLOATING; break; case INPUT_ANALOG: gpio_mode = GPIO_INPUT_ANALOG; break; case INPUT_PULLUP: gpio_mode = GPIO_INPUT_PU; break; case INPUT_PULLDOWN: gpio_mode = GPIO_INPUT_PD; break; case PWM: gpio_mode = GPIO_AF_OUTPUT_PP; pwm = true; break; case PWM_OPEN_DRAIN: gpio_mode = GPIO_AF_OUTPUT_OD; pwm = true; break; default: return; } GPIOPortX().pinMode(PIN, gpio_mode); (void)pwm; // TODO: implement timer start/stop } }; #define fastWrite(pin,value) do { (value) ? pin.high() : pin.low(); } while(0)

Paulvdh
Пт 28 декабря 2018 г. 12:27
Я возился с С в течение 30 лет и с C ++ на намного короче.
Совсем недавно я пытаюсь начать с STM32F103 / Blue Pills / Maple Mini's.

Я думаю, что мне очень нравится шаблонный способ обработки gpio, но я думаю, что пока мне разумно позволить этому, пока я больше не знаком с самим STM32F103.

В поисках «материала» для STM32 я нашел кучу библиотек / фреймворков / ядер / ядер на основе шаблонов, и я думаю, что было бы неплохо поделиться некоторыми (довольно случайными) заметками / ссылками здесь:

- XPCC
http: // xpcc.io/betparted/
https: // github.com/roboterclubaachen/xpcc
http: // блог.Салкиний.com/typesafe-regi ... ss-in-c ++/
http: // www.поля.Лейденунив.nl/~ moene/home/books/

- Квасир
https: // github.com/kvasir-io/kvasir

- BMPTK
Набор для инструментов для программирования голой металлы
https: // www.голосование.NL/BMPTK/DOCS/INDEX.HTML
https: // www.YouTube.com/watch?v = mnpfsuzb3vs

- Шаблоны
Мини Дэйви Джонс также делает это с шаблонами:
https: // www.YouTube.com/watch?v = a_sas93clgk

- Jeelabs / Jeenode & Шаблоны:
ViewTopic.PHP?F = 42&t = 4460&P = 51937#P51937
https: // jeelabs.org/projects/jeeh/
https: // jeelabs.org/2018/

https: // chackaday.IO/Project/21045-STM32 ... оценка

СПИ-3 провода