//Обработка прерывания по спаду напряжения на INT0 ISR(INT0_vect) { _delay_ms(10); reg++; //при нажатии на кнопку Увеличиваем значение переменной reg на 1 if (reg==4) reg=0; //Если досчитали до 4, то reg=0 }
void INTinit() { GIMSK=(1<<6); //Разрешаем прерывание INT0 MCUCR=(1<<0)|(1<<1); //Прерывыание по ниспадающему форонту (с 1 на 0); ISC01=1, ISC00=1 }
int main (void) { DDRB=(1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7); //Порт В на ВЫХод
//Обработка прерывания по спаду напряжения на INT0 ISR(INT0_vect) { _delay_ms(10); reg++; //при нажатии на кнопку Увеличиваем значение переменной reg на 1 if (reg==4) reg=0; //Если досчитали до 4, то reg=0 }
int main (void) { DDRB=(1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7); //Порт В на ВЫХод
Зря вы столько кода лишнего вставили. Тяжело анализировать Спойлер
Код:
ПЕРВЫЙ ВАРИАНТ
void INTinit() { GIMSK=(1<<6); //Разрешаем прерывание INT0 MCUCR=(1<<0)|(1<<1); //Прерывыание по ниспадающему форонту (с 1 на 0); ISC01=1, ISC00=1 } int main (void) { INTinit(); // вызываем функцию инициализации прерываний sei(); //Глобальное разрешение прерываний while (1) { } }
ВТОРОЙ ВАРИАНТ
int main (void) { GIMSK=(1<<6); //Разрешаем прерывание INT0 MCUCR=(1<<0)|(1<<1); //Прерывыание по ниспадающему форонту (с 1 на 0); ISC01=1, ISC00=1 sei(); //Глобальное разрешение прерываний while (1) { } }
Чисто мое мнение, не вижу никакого смысла использовать лишнюю функцию. Видел так делают, когда принимают или отправляют значение, так называемые геттеры и сеттеры, но это не тот случай.
MCUCR=(1<<0)|(1<<1); //Прерывыание по ниспадающему форонту (с 1 на 0); ISC01=1, ISC00=1
Вот так писать не надо. Специально для наглядности кода существуют константы: MCUCR = (1<<ISC01 | 1<<ISC00); // прерывание INT0 по спаду
Цитата:
Видел так делают, когда принимают или отправляют значение, так называемые геттеры и сеттеры, но это не тот случай.
Вроде как это делается для большей структуризации кода и некоторого увеличения его безопасности. В контроллерах, где идет прямое обращение к регистрам, это лишнее.
небольшой вопрос по языку си (правда на примере регистров stm32). Для чего применяется запись uint32_t? Это какой-то намек на 32-разрядные числа? Вот пример, нужно сбросить бит в регистре: RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); Для чего здесь первый раз применяется эта конструкция и для чего второй?
Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей.
Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре.
Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств.
uint32_t - unsigned integer 32-битный. Не трудно догадаться, что этот тип применяется для целочисленных беззнаковых 32-битных переменных.
Т.е. uint_32t это тоже самое для программы, что unsigned int в объявлении переменных? Я всегда это подозревал. Но тогда как понять запись вида ((uint32_t)~(RCC_CFGR_SW))?
Не совсем. unsigned int не везде 32-битный (в тех же AVR - 16-битный, например). Использование типов вроде uint32_t избавляет от необходимости помнить эти размеры в разных архитектурах, упрощает код и обеспечивает лучшую переносимость кода между разными платформами.
Собственно, то же и с приведением типов. Если имеем, к примеру, #define SOME 4, то (uint32_t)(~((uint32_t)SOME) гарантировано даст 32-битную инверсию 32-битной четвёрки, т.е., 0xFFFFFFFB. Тогда как, например, просто (uint32_t)(~SOME) вполне может дать результат 0x0000FFFB на некоторых архитектурах.
Не совсем. unsigned int не везде 32-битный (в тех же AVR - 16-битный, например). Использование типов вроде uint32_t избавляет от необходимости помнить эти размеры в разных архитектурах, упрощает код и обеспечивает лучшую переносимость кода между разными платформами.
Собственно, то же и с приведением типов. Если имеем, к примеру, #define SOME 4, то (uint32_t)(~((uint32_t)SOME) гарантировано даст 32-битную инверсию 32-битной четвёрки, т.е., 0xFFFFFFFB. Тогда как, например, просто (uint32_t)(~SOME) вполне может дать результат 0x0000FFFB на некоторых архитектурах.
Здравствуйте. Подскажите по поводу использования таймера в atmega8. Есть таймер 16 бит. Сконфигурирован таким образом чтобы на выход OCR1B в режиме fast PWM 9bit был меандр со скважностью 50%. Это для пищалки. Хочу использовать этот же таймер для прерывания по совпадению с OCR1A. Но МК не входит в прерывание. Я так понимаю не до тикивает до нужного значения TCNT1. Можно ли вообще использовать часть таймера для генерации ШИМ и отсчета времени в прерывании? Спасибо.
while (1) { _delay_ms(500); if ( MFRC522_Request( PICC_REQIDL, card_num ) == MI_OK ) { if ( MFRC522_Anticoll( card_num ) == MI_OK ) { TX_ENABLE; GREENLED_ON; uart_puts("CN"); //Последовательность о передаче номера карты for (i = 0; i < 5; i++ ) { uart_putc(card_num[i]); //5 байт номера кары } uart_puts("\r"); //Символ конца строки RX_ENABLE; GREENLED_OFF; } } } } Заметил ошибку в инициализации таймера TCCR1A = (1<<COM1B1)|(1<<COM1B0)|(1<<WGM12)|(1<<WGM11); WGM12 находится в другом регистре. Исправил на TCCR1A = (1<<COM1B1)|(1<<COM1B0)|(1<<WGM11); TCCR1B = (1<<WGM12); Проблема остается
ШИМ работает в 9ти битном режиме, т.е. максимальное число это 0х01FF (511). Таймер дотикивает до 511ти и сбрасывается?
_________________ Немного нервов и девайс готов
Последний раз редактировалось Vergilium Ср июл 12, 2017 11:38:50, всего редактировалось 1 раз.
В ДШ, буружуйским по белому написано, что счетчик будет считать до 0x01FF в 9битном режиме, что логично, а не до регистра OCR. Или уменьшайте OCR1A или используйте прерывание по переполнению таймера.
_________________ Добро всегда побеждает зло. Поэтому кто победил - тот и добрый.
Подскажите по передаче UART с помощью кольцевого буфера и на прерываниях. В принципе все работает хорошо и очень быстро. Но дело в том, что там же нужно задавать размер этого самого буфера. Это хорошо если заранее знаешь размер передаваемых данных, а если нет, то как быть? Можно как то заранее узнать количество передаваемых байт и потом задать нужный буфер? Есть только одна мысль, сначала поместить эту строку во временный массив, пройтись циклом, пока не закончаться значения в массиве, инкрементируя при этом счетчик, вот он и будет размером буфера. Не знаю насколько это правильно. Еще вычитал что есть функция sizeof() для массивов Спойлер
void uart_init( void ) //функция инициализации UART { //настройка скорости обмена UBRR0H = 0; UBRR0L = 15; // скорость 57600 для 14 745 600 //разрешить прием и передачу данных UCSR0B = (1<<TXCIE0)|(1<<TXEN0); //включаем прерывание по передаче и саму передачу //8 бит данных, 1 стоп бит, без контроля четности UCSR0C = (1<<UCSZ01) | (1<<UCSZ00);
//помещает символ в буфер, инициирует начало передачи void USART_PutChar(unsigned char sym) { //если модуль usart свободен и это первый символ //пишем его прямо в регистр UDR if(((UCSR0A & (1<<UDRE0)) != 0) && (!txCount)) { UDR0 = sym; } else { if (txCount < SIZE_BUF) //если в буфере еще есть место { usartTxBuf[txBufTail] = sym; //помещаем в него символ txCount++; //инкрементируем счетчик символов txBufTail++; //и индекс хвоста буфера if (txBufTail == SIZE_BUF) { txBufTail = 0; } } } }
//обработчик прерывания по завершению передачи ISR(USART_TX_vect) { if (txCount > 0) //если буфер не пустой { UDR0 = usartTxBuf[txBufHead]; //записываем в UDR символ из буфера txCount--; //уменьшаем счетчик символов txBufHead++; //инкрементируем индекс головы буфера if (txBufHead == SIZE_BUF) { USART_FlushTxBuf(); } } }
// USART.H
#ifndef USART_H #define USART_H
#include <avr/io.h> #include <avr/interrupt.h>
//размер буфера #define SIZE_BUF 65
void uart_init( void ); unsigned char USART_GetTxCount(void); //взять число символов передающего буфера void USART_FlushTxBuf(void); //очистить передающий буфер void USART_PutChar(unsigned char sym); //положить символ в буфер void USART_SendStr(char * data); //послать строку по usart`у
Но дело в том, что там же нужно задавать размер этого самого буфера. Это хорошо если заранее знаешь размер передаваемых данных, а если нет, то как быть?
Выбрать его больше [либо равным] длины максимально возможной посылки, и перед помещением в него новой порции данных отслеживать состояние передатчика. Но в этом случае кольцевой буфер и не нужен. Либо перед помещением новой порции данных проверять наличие там места - буфер ведь кольцевой и передатчик его "обмолачивает" пока в нём что-то есть. А дело программы - подкидывать новые данные в хвост.
Можно как то заранее узнать количество передаваемых байт и потом задать нужный буфер?
буфера разного размера -> работа с динамическим выделением памяти -> передатчик должен отслеживать работу со списком буферов - кмк, заморочно получается.
Еще вычитал что есть функция sizeof() для массивов
Это не функция - а оператор определяющий размер содержимого в момент компиляции - т.е. во время работы программы это уже будет константа.
Это теория была, а по коду: добавьте в USART_PutChar и USART_SendStr возвращаемое значение bool для успеха попытки помещения в буффер и проверяйте его в своей программе - если "отослалось" успешно - забыли, если нет - повторите попытку послать попозже.
_________________ Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR!
Выбрать его больше [либо равным] длины максимально возможной посылки, и перед помещением в него новой порции данных отслеживать состояние передатчика. Но в этом случае кольцевой буфер и не нужен. Либо перед помещением новой порции данных проверять наличие там места - буфер ведь кольцевой и передатчик его "обмолачивает" пока в нём что-то есть. А дело программы - подкидывать новые данные в хвост.
У меня видимо где-то в коде ошибка, буфер должен идеально соответствовать размеру передаваемых данных, ни больше ни меньше. Если он больше, то получается фигня, данные дублируются, теряются. Вот такое происходит (первая строка правильная) Спойлер Если было бы возможным задать размер буфера с запасом, то это для меня был бы отличный вариант. У меня задача для которой понадобилось два UART, нужно через определенные промежутки времени слать команды двум разным датчикам, а от одного еще и получать. Хотелось отказаться от программной реализации UART, которая довольно ресурсозатратна, вот и было решено оставить аппаратный и коммутировать одно или другое устройство . Команды разные размер их тоже разный и скорости передачи отличаются (57600 и 9600), вот в этом и сложность.
У меня видимо где-то в коде ошибка, буфер должен идеально соответствовать размеру передаваемых данных, ни больше ни меньше. Если он больше, то получается фигня, данные дублируются, теряются.
У вас буффер "хвостом" вперёд ползёт (что, впрочем, для МК безразлично). А txCount - дублирующая сущность - высчитывайте количество неотправленых из разницы головы к хвосту (с учётом "заворота", конечно-же). Тем более что меняется txCount как в основном "потоке" так и в прерывании - начните с причисления его к Ордену Волатайла Приснопамятного.
У меня задача для которой понадобилось два UART, нужно через определенные промежутки времени слать команды двум разным датчикам, а от одного еще и получать. [....] вот и было решено оставить аппаратный и коммутировать одно или другое устройство.
Фишка кольцевого буфера в его асинхронной автономности - кидаем мясо в мясорубку, а котлеты с другой стороны аккуратно выпадают. Коммутация предполагает синхронизацию с тем фактом, что вся посылка к текущему адресату ушла (включая замыкающий байт!) - и не проще ли будет переключиться на обычный буффер - заряжать всегда его с нуля и не позволять преключаться пока передатчик в busy? И да, "от одного ещё и получать" - синхронные ответы на команды? В противном случае - сами понимаете что будет.
_________________ Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR!
и не проще ли будет переключиться на обычный буффер
Обычный в смысле не кольцевой? А скорость будет такая же быстрая как с кольцевым? Я просто всего пару месяцев изучаю МК так что особо не понимаю разницы. Мне главное чтобы работало быстро. А то я сравнивал UART без прерываний (ожидание флага готовности), так отправка 60 байт занимала время МК на 8 миллисекунд, с прерываниями максимум 150 микросекунд, разница колоссальная.
А задумка такая подключаем первый датчик, отправляем ему команду получаем ответ, выводим эти данные на дисплей после обработки. Затем, через несколько секунд отключаем первый и подключаем второй датчик, отправляем ему данные, ответа от него не будет. Затем через несколько секунд отключаем второй подключаем первый, шлем команду и т. д.
Обычный в смысле не кольцевой? А скорость будет такая же быстрая как с кольцевым?
Если теоретизировать - то зависит от задачи. Представьте себе, что лежите вы с пулемётом на огневом рубеже и лента у пулемёта закольцована. Подполз второй номер с цинком - набил в это кольцо десяток-другой патронов, разбудил вас сапогом в бок - нажали вы на спуск и пошла стрельба пока есть чем. Это кольцевой буфер. А линейный буфер - это если у пулемёта питание магазинное - то второй номер вам боеприпасы в виде этих самых магазинов подаёт, смена которых гарантировано ведёт к задержкам в стрельбе. В кольцевом-же - набивание патронов может производиться параллельно основному процессу и не задерживать процесс истребления басурманов. Но моментальная "скорострельность" в обоих случаях одинакова. А общая "скорострельность" да - для линейного будет слегка пониже. Но задача у вас ведь не непрерывное подавление огнём, при котором такие задержки критичны, а попеременное "отоваривание" двух целей фиксированным количеством пуль - где зарядка нового "магазина" во время переноса огня с одной цели на другую, не мешает выполнению основной задачи. А UART что из кольцевого буфера, что из линейного будет данные кушать одинаково быстро. Кольцевой - лишь способ организации безостановочной отсылки данных. А линейный проще - зарядили, запустили и ждём пока всё не уйдёт. Я бы убрал из программы head, tail, count, заведя вместо них один index, загружал каждую посылку в буффер с нулевого индекса и с того-же нулевого индекса и начинал отсылку. Буффер размером с максимально возможную посылку. Окончание передачи - index на байте, следующем за концом отсылаемых данных && состояние передатчика не BUSY.
_________________ Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR!
Спасибо большое. После такого объяснения с приведением аналогии я наконец-то понял как все работает. Да пожалуй линейный буфер как раз для моего случая.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 45
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения