Добрый день. Решил помигать светодиодиком на STM8. В Platformio установил соответствующий пакет, и выбрал пример native-blink (пока пробую без библиотек). В коде примера смотрю на настройку пина, и вижу следующее (привожу лишь необходимые на мой взгляд куски:
То есть, для настройки пина на выход пуш-пулл с быстрыми фронтами, надо выставить соответвующий бит (5 по счету) в 3-х регистрах. И это делается этой хитрой конструкцией. Почему она для меня хитрая ? Потому что в AVR и PIC я привык выставлять биты конструкцией вида DDRB |= 1<<5; Ну и сбрасывать соответственно похожим образом: DDRB &= ~(1<<5); Залез в хидер, нашёл там union, внутри которого структура с битовыми полями. Спойлер
Код:
/** Port A data direction register (DDR at 0x5002) */ union {
/// bytewise access to DDR uint8_t byte;
/// bitwise access to register DDR struct { BITFIELD_UINT DDR0 : 1; // bit 0 BITFIELD_UINT DDR1 : 1; // bit 1 BITFIELD_UINT DDR2 : 1; // bit 2 BITFIELD_UINT DDR3 : 1; // bit 3 BITFIELD_UINT DDR4 : 1; // bit 4 BITFIELD_UINT DDR5 : 1; // bit 5 BITFIELD_UINT DDR6 : 1; // bit 6 BITFIELD_UINT DDR7 : 1; // bit 7 }; // DDR bitfield
/// register _PORT_DDR reset value #define sfr_PORT_DDR_RESET_VALUE ((uint8_t) 0x00)
} DDR;
но как сбрасывать, так и не понял. Как с помощью этой конструкции сбросить бит в регистре ?
LED_PORT.DDR.byte - это обращение ко всем битам, то есть к /// bytewise access to DDR uint8_t byte; И можете работать с ним как раньше.
Union объединяет эти определения или делает эквивалентным их или проецирует этот байт на структуру и обратно (не знаю, как лучше сказать...) то есть, к биту можно обратиться как LED_PORT.DDR.DDR0 = 0
...к биту можно обратиться как LED_PORT.DDR.DDR0 = 0
Вот, такое обращение с использованием битовых полей для меня логично и понятно)) Ранее с обьединениями дела не имел, лишь вскользь читал в Кернигане и Ричи. То есть, для сброса бита при обращении к структуре объединения как к целому байту мне необходимо писать LED_PORT.DDR.byte &= ~(LED_PIN); ? И правильно ли я понял, что установку битов лучше производить конструкцией типа LED_PORT.DDR.byte |= LED_PIN, иначе если делать как в примере, то все остальные биты регистра будут сбрасываться ?
То есть, для сброса бита при обращении к структуре объединения как к целому байту мне необходимо писать LED_PORT.DDR.byte &= ~(LED_PIN); ?
да, но только со сдвигом единички, то есть, (1 << LED_PIN)
Цитата:
установку битов лучше производить конструкцией типа LED_PORT.DDR.byte |= LED_PIN
не знаю, как лучше с точки зрения языка. Конструкция в любом случае будет красивше, так как займёт одну строку, вместо восьми. Однако, возможно, есть алгоритм, где краисвше обратиться в цикле к каждому биту. Ещё может быть разница с точки зрения компилятора.
Цитата:
то все остальные биты регистра будут сбрасываться?
обращаясь к .byte Вы обращаетесь ко всем битам,, соответсвенно. либо сбросятся, либо установятся. Обращаясь к .DDR0 - обращаетесь только к этому биту, никакие другие не будут затронуты,
Вообще, это очень удобно. Например, можете сделать такую структуру:
Код:
/** Port A data direction register (DDR at 0x5002) */ union {
.....
/// bitwise access to register DDR struct { BITFIELD_UINT DDR03 : 4; // bit 0...bit 3 BITFIELD_UINT DDR47 : 4; // bit 4...bit 7 }; // DDR bitfield
/// register _PORT_DDR reset value #define sfr_PORT_DDR_RESET_VALUE ((uint8_t) 0x00)
} DDR;
и в итоге получить обращение к младшему и старшему 4-битным словам. И если вся логика построена на таких словах, это будет удобно.
Зарегистрирован: Вс мар 27, 2022 15:49:30 Сообщений: 16
Рейтинг сообщения:0
Да, тут всё правильно ответили - через CR1 и CR2 задаются режимы работ, в ODR пишется собственно байт на выход порта. Но не стОит останавливаться на этом, есть ещё и альтернативные функции... лучше не программно дёргать, а к таймеру подключить. У меня, например, в управляшке для бесколлекторного мотора TIM2 работает генератором сигнала (TIM2_OC2Init(TIM2_OCMODE_TOGGLE, TIM2_OUTPUTSTATE_ENABLE,CCR2_Val, TIM2_OCPOLARITY_HIGH); - переключает выход с программируемой частотой), а первый таймер - частотомер - захватывает фронты с датчика и измеряет скорость вращения.
Здравствуйте! Подскажите как в STM8S103 заставить работать АЦП2. В нете везде примеры только с АЦП1. Мне же нужно реализовать два независимых канала измерения. Однин на АЦП1 как "Сторож" напряжения. Второй на АЦП2 измерение температуры. Перерыл кучу инфы, так и не получилось заставить измерять по АЦП2. Брал за основу исходник с АЦП1 - измерения происходят нормально. Перенастраиваю исходник на АЦП2 - и не работает. Компилятор SDCC.
/* Right-align data */ //ADC1_CR2 |= (1 << ADC1_CR2_ALIGN); // включить выравнивание по правому краю ADC2_CR2 |= (1 << ADC2_CR2_ALIGN); // включить выравнивание по правому краю
//ADC2_CSR |= (1 << ADC2_CSR_EOCIE); // включить формирование прерываний
/* Wake ADC from power down */
// ADC1_CR1 |= (1 << ADC1_CR1_ADON); //включить питание на АЦП1, второй повтор начнет преобразование ADC2_CR1 |= (1 << ADC2_CR1_ADON); //включить питание на АЦП2, второй повтор начнет преобразование
Ну надо как-то в него добавить второй АЦП, так как их там один.
Вот же шшшшш..... Два дня убил на эту хрень. Перерыл кучу инфы. В учебниказ по STM8 написано что два АЦП. А в даташит именно на этот контроллер посмотреть не додумался. Благодарю за прозрение.
Зарегистрирован: Ср янв 06, 2010 22:02:25 Сообщений: 210 Откуда: Уфа сити
Рейтинг сообщения:0
Добрый день! Пытаюсь обуздать STM8. Задача - сымитировать работу сдвигового регистра. На всякий случай поясню суть: после сигнала latch идет серия тактовых сигналов, по которым отдаем в DATA биты по очереди. Проблема в том, что что latch читается легко, а вот с чтением CLK возникли проблемы. Не пойму, что не так, но либо читается один импульс, либо не читается вообще. СТМка работает на частоте 16мгц.
void proc(void){ while(GPIO_ReadInputPin(LATCH_PORT,LATCH_PIN)==0){}; // Ждем изменения latch for (u8 i = 0; i < 8; i++) { if (data & (1 << i)) dataL(); // сброс бита else dataH(); // установка бита
while( GPIO_ReadInputPin(CLK_PORT, CLK_PIN)==0){}; // Ждем изменения clk }
dataH(); }
В строке while( GPIO_ReadInputPin(CLK_PORT, CLK_PIN)==0) ожидание что 0, что 1 дает один и тот же результат - биты отдаются сразу пачкой, такое ощущение, что чтение порта не работает, хотя сконфигурирован как вход GPIO_Init(CLK_PORT, (GPIO_Pin_TypeDef)(CLK_PIN), GPIO_MODE_IN_FL_NO_IT);
Подобный код на ардуине работал превосходно, даже с учетом тормозов фреймворка Arduino, а тут, на голой СТМке как будто камня не хватает для выборки сигнала..
_________________ Что в цивилизованном мире называют "устаревшие технологии", в России зовется "технологии, проверенные временем"
Последний раз редактировалось Ромыч Вт окт 25, 2022 16:14:42, всего редактировалось 1 раз.
Зарегистрирован: Вс мар 27, 2022 15:49:30 Сообщений: 16
Рейтинг сообщения:0
1. Это в какой среде написано? 2. А для чего - просто для развлекательно-познавательных целей? Вообще-то SPI можно соответственно задаче сконфигурировать. Ну или хотя бы CLK сконфигурировать с прерыванием от изменения уровня - тогда будет точно по переходу 1->0 или 0->1 срабатывать... Здесь же фактически ждётся не изменение CLK, а только пока он равен нулю.
Ромыч, код - адова жесть! Можно ведь использовать таймер или на худой конец прерывания. Не приведено, что внутри функций GPIO_ReadInputPin, dataL, dataH и data1H - об этом нужно догататься самостоятельно? Первая функция сильно похожа на SPL, неужто на несчастную STM8 еще и это дерьмище вкорячили? Жуть!
В общем, прочитав этот код я совершенно не могу даже логику работы понять!
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ
Зарегистрирован: Ср янв 06, 2010 22:02:25 Сообщений: 210 Откуда: Уфа сити
Рейтинг сообщения:0
Написано в IAR + SPL. Цели - познавательно-развлекательные. SPI, к сожалению, уже занят... CLK вешал на прерывание, но оно тригеррится слишком поздно, когда вся пачка сигналов уже прошла. Как я понял, перед прерыванием выполняются текущие инструкции и (скорее всего) МК работает со стеком для подготовки прерывания. Соответственно, код из обработчика выполняется слишком поздно...
Цитата:
Здесь же фактически ждётся не изменение CLK, а только пока он равен нулю.
не совсем. первый бит выставляется сразу после Latch, далее он должен поменяться после CLK, потому, чисто в целях отладки, без разницы нуля ждать или единицы, максимум, возможен пропуск одного цикла Clk. Проблема в том, что while не работает... не могу понять почему.
Цитата:
Первая функция сильно похожа на SPL, неужто на несчастную STM8 еще и это дерьмище вкорячили? Жуть!
SPL и есть.. а где лучше писать? в STM я совсем новичок, и в местных сортах пенного не разбираюсь. пробовал родную IDE, но что то с космиком не сдружился.. может посоветуете что лучше? ясное дело, что ASM рулит, но пока не готов в него лезть. через ардуиновскую библу тоже нет желания работать.
Зарегистрирован: Вс мар 27, 2022 15:49:30 Сообщений: 16
Рейтинг сообщения:0
И ещё вопрос - какой конкретно контроллер? Если 103f3p6, то у него по умолчанию тактовая /8, т.е. 2 MHz. Чтобы было 16: CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
И ещё вопрос - какой конкретно контроллер? Если 103f3p6, то у него по умолчанию тактовая /8, т.е. 2 MHz. Чтобы было 16: CLK_HSIPrescalerConfig(CLK_PRESCALER_HSIDIV1);
да, именно его, на отладочной чинской платке. CLK_PRESCALER_HSIDIV1 стоит, потому и уточнил, что камень работает на 16мгц
_________________ Что в цивилизованном мире называют "устаревшие технологии", в России зовется "технологии, проверенные временем"
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения