VHEMaster, вы это мне или кому-то из предыдущих сообщений?:)
Вопросы по С/С++ (СИ)
- Мikа
- Потрогал лапой паяльник
- Сообщения: 343
- Зарегистрирован: Пн апр 01, 2013 15:13:40
- Откуда: Москва
Re: Вопросы по С/С++ (СИ)
Это моя неопытность:) Никакого смысла или преимущества у XOR я не придумал
И до кучи тогда еще вопрос: как будет правильнее сбрасывать бит? Так (~(1<<0)) или так (0<<1) или второй вариант вообще работать не будет?:)
VHEMaster, вы это мне или кому-то из предыдущих сообщений?:)
VHEMaster, вы это мне или кому-то из предыдущих сообщений?:)
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Потому что хочу научиться.
- Реклама
-
pcb
- Опытный кот
- Сообщения: 833
- Зарегистрирован: Пт авг 12, 2011 09:14:27
- Откуда: Млечный путь/Земля/РФ/Екатеринбург
Re: Вопросы по С/С++ (СИ)
PORTB&=~(1<<pin); обнуляем битМikа писал(а):И до кучи тогда еще вопрос: как будет правильнее сбрасывать бит? Так (~(1<<0)) или так (0<<1) или второй вариант вообще работать не будет?:)
PORTB/=(1<<pin); ставим бит
Разработал:
-BLDC
-ФУОЗ/МПСЗ
-SMART BMS
-ECU/EDC на STM32F4(43%)+CPLD(57%)
-Моноинжектор на ATSAMD20G16
-контроллер эффектов для RGB LED ленты
-умные часы/обратный счет/секундомер
-устройство измерения емкости АКБ
-BLDC
-ФУОЗ/МПСЗ
-SMART BMS
-ECU/EDC на STM32F4(43%)+CPLD(57%)
-Моноинжектор на ATSAMD20G16
-контроллер эффектов для RGB LED ленты
-умные часы/обратный счет/секундомер
-устройство измерения емкости АКБ
- VHEMaster
- Потрогал лапой паяльник
- Сообщения: 374
- Зарегистрирован: Сб июл 14, 2012 09:20:09
- Откуда: Украина, город Полтава
Re: Вопросы по С/С++ (СИ)
Я это тому, кому нужна помощьМikа писал(а):VHEMaster, вы это мне или кому-то из предыдущих сообщений?:)
- vitalik_1984
- Поставщик валерьянки для Кота
- Сообщения: 2482
- Зарегистрирован: Пт авг 27, 2010 05:57:06
- Откуда: Тюмень
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
pcb писал(а): PORTB/=(1<<pin); ставим бит
Код: Выделить всё
PORTB|=(1<<pin); //ставим бит - Мikа
- Потрогал лапой паяльник
- Сообщения: 343
- Зарегистрирован: Пн апр 01, 2013 15:13:40
- Откуда: Москва
Re: Вопросы по С/С++ (СИ)
Спасибо, парни
Да, вопрос из азбуки, но я предпочитаю узнать ответ у живых людей, а не у статьи, если это возможно
Сорри за оффтоп 
Ещё вопрос, относительно флагов прерываний. Суть такова, что после вызова прерывания и выполнения всего, что с ним связано, прерывание выполняется ещё раз. Как я понимаю - это дребезг кнопки. Но не понятно вот что: первое, что делает прерывание - запрещает прерывания. Потом идёт ожидание 250 мс. Потом выполняется всё, что оно за собой тянет. И, главное, в самом конце, перед разрешением прерываний, я сбрасываю все флаги INT прерываний.
Напомню, для понятности: обработчик прерывания "включает кусок выполняемого кода, делая его условие истинным".
После этого прерывание вызывается снова. О продолжающемся дребезге речи быть не может, тк всё это дело выполняется больше 5 секунд.
Саму проблему повторного ыполнения кода я решил тем, что переместил w=0; туда, где оно сейчас из Было тут.
Но мне хотелось бы понять, откуда берётся прерывание.
GIFR=0xb11100000; // Сбрасываем флаги прерываний по - в этот регистр я и 000 и 111 записывал, всё одно и то же.
Про обнуление флагов да и вообще про прерывания INT я читал тут
Конкретно о сбросе флагов прерываний:
Флаги сбрасываются аппаратно, когда вызывается обработчики прерываний. Также их можно сбросить программно, записав в регистр единицы.
Ещё вопрос, относительно флагов прерываний. Суть такова, что после вызова прерывания и выполнения всего, что с ним связано, прерывание выполняется ещё раз. Как я понимаю - это дребезг кнопки. Но не понятно вот что: первое, что делает прерывание - запрещает прерывания. Потом идёт ожидание 250 мс. Потом выполняется всё, что оно за собой тянет. И, главное, в самом конце, перед разрешением прерываний, я сбрасываю все флаги INT прерываний.
Напомню, для понятности: обработчик прерывания "включает кусок выполняемого кода, делая его условие истинным".
Код: Выделить всё
ISR( INT1_vect )
{
GICR=0b00000000; // Запрет прерываний
_delay_ms(250); // Ожидание
LcdWriteData('P'); // Оповещение о том, что прерывание сработало
w=1; // "Включение условия"
}
if (w==1)
{
//Выполняемый код
[b]Было тут[/b]
GIFR=0xb11100000; // Сбрасываем флаги прерываний по
GICR=0b10000000; // Разрешаем прерывания
_delay_ms(500);
[b]w=0;[/b]
}
Саму проблему повторного ыполнения кода я решил тем, что переместил w=0; туда, где оно сейчас из Было тут.
Но мне хотелось бы понять, откуда берётся прерывание.
GIFR=0xb11100000; // Сбрасываем флаги прерываний по - в этот регистр я и 000 и 111 записывал, всё одно и то же.
Про обнуление флагов да и вообще про прерывания INT я читал тут
Конкретно о сбросе флагов прерываний:
Спойлер
Последний регистр, имеющий отношение к внешним прерываниям, - это статусный регистр GIFR (General Interrupt Flag Register). В нем содержатся флаги, устанавливаемые в случае формирования запроса на внешнее прерывание.Флаги сбрасываются аппаратно, когда вызывается обработчики прерываний. Также их можно сбросить программно, записав в регистр единицы.
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Потому что хочу научиться.
- Реклама
- eess9
- Вымогатель припоя
- Сообщения: 672
- Зарегистрирован: Ср фев 29, 2012 01:58:32
- Откуда: Харьков, Украина
Re: Вопросы по С/С++ (СИ)
А что за странная запись?
Если вы хотите в 16-ричной системе, то 0xFF, если в двоичной - 0b11111111.
0xb -??? Странно что компилятор пропустил такое
Если флаг надо сбросить, то надо записать
Код: Выделить всё
GIFR=0xb11100000; // Сбрасываем флаги прерываний 0xb -??? Странно что компилятор пропустил такое
Если флаг надо сбросить, то надо записать
Код: Выделить всё
GIFR=0xFF;- Вложения
-
- 1.jpg
- (92.37 КБ) 322 скачивания
- Мikа
- Потрогал лапой паяльник
- Сообщения: 343
- Зарегистрирован: Пн апр 01, 2013 15:13:40
- Откуда: Москва
Re: Вопросы по С/С++ (СИ)
Это называется "Привет, я Миша и я днище"eess9 писал(а):А что за странная запись?Если вы хотите в 16-ричной системе, то 0xFF, если в двоичной - 0b11111111.Код: Выделить всё
GIFR=0xb11100000; // Сбрасываем флаги прерываний
0xb -??? Странно что компилятор пропустил такое
Если флаг надо сбросить, то надо записатьКод: Выделить всё
GIFR=0xFF;
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Потому что хочу научиться.
- Аlex
- Модератор
- Сообщения: 4614
- Зарегистрирован: Чт мар 18, 2010 23:09:57
- Откуда: Планета Земля
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
А чего бы ему не пропустить ? 0xb - это 11 в десятичной. Синтаксис для компилятора вполне адекватный.0xb -??? Странно что компилятор пропустил такое
- Мikа
- Потрогал лапой паяльник
- Сообщения: 343
- Зарегистрирован: Пн апр 01, 2013 15:13:40
- Откуда: Москва
Re: Вопросы по С/С++ (СИ)
А теперь озадачивает счётчик ATmega32 TC1, дающий прерывание по совпадению с числом 
В обработчике он должен последовательно два раза вывести на дисплей число, которое он насчитал на момент вывода этого самого числа.
Вот обработчик:
ISR (TIMER1_COMPA_vect)
{
//timer++;
LcdWriteData('1'); //Пишем на дисплей
LcdWriteData('_'); //Пишем на дисплей
showMore(TCNT1|0x30); //Пишем на дисплей число из регистра, в котором лежит число, насчитанное таймером.
LcdWriteData(' '); //Пишем на дисплей
LcdWriteData('2'); //Пишем на дисплей
LcdWriteData('_'); //Пишем на дисплей
showMore(TCNT1|0x30); //Пишем на дисплей число из регистра, в котором лежит число, насчитанное таймером.
TIMSK&=(~(1<<OCIE1A)); //Запрещаем прерывание по таймеру
}
По-идее всё просто) Вот что пишет дисплей: 1_15676 2_15671. Но как второе число может быть меньше первого? Оо То, что таймер проходит по второму кругу исключено: частота 16МГц\1024. Таймер 16ти разрядный. В секунду считает до 15625. Так же для проверки прерывание по переполнению таймера выводит "F" на дисплей. Но в обработчике видно, что разница между выводами информации всего в паре команд.
Да, если добавить между выводами первого и второго значения какую-то задержку, больше 2 мс, то он показывает адекватный результат.
В обработчике он должен последовательно два раза вывести на дисплей число, которое он насчитал на момент вывода этого самого числа.
Вот обработчик:
ISR (TIMER1_COMPA_vect)
{
//timer++;
LcdWriteData('1'); //Пишем на дисплей
LcdWriteData('_'); //Пишем на дисплей
showMore(TCNT1|0x30); //Пишем на дисплей число из регистра, в котором лежит число, насчитанное таймером.
LcdWriteData(' '); //Пишем на дисплей
LcdWriteData('2'); //Пишем на дисплей
LcdWriteData('_'); //Пишем на дисплей
showMore(TCNT1|0x30); //Пишем на дисплей число из регистра, в котором лежит число, насчитанное таймером.
TIMSK&=(~(1<<OCIE1A)); //Запрещаем прерывание по таймеру
}
По-идее всё просто) Вот что пишет дисплей: 1_15676 2_15671. Но как второе число может быть меньше первого? Оо То, что таймер проходит по второму кругу исключено: частота 16МГц\1024. Таймер 16ти разрядный. В секунду считает до 15625. Так же для проверки прерывание по переполнению таймера выводит "F" на дисплей. Но в обработчике видно, что разница между выводами информации всего в паре команд.
Да, если добавить между выводами первого и второго значения какую-то задержку, больше 2 мс, то он показывает адекватный результат.
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Потому что хочу научиться.
Re: Вопросы по С/С++ (СИ)
Ух ты! А я проглядел. Мikа, Вы очень изящно выстрелили себе в ногу.А чего бы ему не пропустить ? 0xb - это 11 в десятичной.
Прерывания лучше не нагружать работой с дисплеем, ибо это долгое дело, а они должны быть как можно короче. Лучше в прерывании ставьте флаг, а в главном цикле по нему что-то делайте.
Кстати, Вы учли, что в момент прерывания таймер не обнуляется, и продолжает считать дальше?
Разница между теорией и практикой на практике гораздо больше, чем в теории.
- Мikа
- Потрогал лапой паяльник
- Сообщения: 343
- Зарегистрирован: Пн апр 01, 2013 15:13:40
- Откуда: Москва
Re: Вопросы по С/С++ (СИ)
YS, да, в рабочем варианте программы прерывания только флаги и выставляют. Ну или делают инкрименты. Всё описанное выше было просто тестом, разбираюсь подробнее, что к чему. то, что таймер не обнуляется, я помню 
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Потому что хочу научиться.
Re: Вопросы по С/С++ (СИ)
Кстати, в чем смысл этой операции:
?
В принципе, | 0x30 делает из цифры код ее символьного представления, если я все правильно помню. Но это верно только для цифр. Для чисел работать, естесственно, не будет.
Где TIMER_INT_PERIOD - желаемый период прерываний. Иначе прерывание происходит ровно столько же раз в секунду, сколько и переполнение, только со сдвигом относительно него, при одном и том же числе в таймере...
Код: Выделить всё
TCNT1|0x30
В принципе, | 0x30 делает из цифры код ее символьного представления, если я все правильно помню. Но это верно только для цифр. Для чисел работать, естесственно, не будет.
Тогда логично было бы добавить строчку типато, что таймер не обнуляется, я помню
Код: Выделить всё
OCR1A+=TIMER_INT_PERIOD;
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Re: Вопросы по С/С++ (СИ)
Здравствуйте!
Написал в IAR AVR на Си операцию записи в EEPROM:
eep_OSCCAL=a;
Смотрю листинг после компиляции и вижу это:
Вопрос: а где вообще код __eeput8_8 ??
Меня интересует, как компилятор реализует запись в EEPROM если у меня записывается то же значение, что и было там? Т. е. подпрограмма тупо перезапишет ячейку, бессмысленно сократив ей жизнь если пишется то же что и было, или же она выполняет проверку различается ли то, что есть и что пишу и запишет только если различается?
Написал в IAR AVR на Си операцию записи в EEPROM:
eep_OSCCAL=a;
Смотрю листинг после компиляции и вижу это:
Спойлер
Код: Выделить всё
\ In segment EEPROM_I, align 1, keep-with-next
11 __eeprom uint8_t eep_OSCCAL=0x40;
\ eep_OSCCAL:
\ 00000000 40 DC8 64
12
13
\ In segment CODE, align 2, keep-with-next
14 int main(void)
\ main:
15 {
16 unsigned char a = 1;
\ 00000000 E001 LDI R16, 1
17
18 eep_OSCCAL=a;
\ 00000002 .... LDI R20, eep_OSCCAL
\ 00000004 .... RCALL __eeput8_8
19 ;
20
21 //Разрешение прерываний
22 __enable_interrupt();
\ 00000006 9478 SEI
23
24 while(1)
\ ??main_0:
\ 00000008 CFFF RJMP ??main_0
25 {
26 ;
27 }
28
29
30 }
Maximum stack usage in bytes:
Function CSTACK RSTACK
-------- ------ ------
main 0 4
Segment part sizes:
Function/Label Bytes
-------------- -----
eep_OSCCAL 1
main 10
10 bytes in segment CODE
1 byte in segment EEPROM_I
10 bytes of CODE memory
1 byte of XDATA memory
Errors: none
Warnings: none
Вопрос: а где вообще код __eeput8_8 ??
Меня интересует, как компилятор реализует запись в EEPROM если у меня записывается то же значение, что и было там? Т. е. подпрограмма тупо перезапишет ячейку, бессмысленно сократив ей жизнь если пишется то же что и было, или же она выполняет проверку различается ли то, что есть и что пишу и запишет только если различается?
- blackx
- Говорящий с текстолитом
- Сообщения: 1518
- Зарегистрирован: Пт дек 28, 2012 21:56:46
- Откуда: St. Petersburg
Re: Вопросы по С/С++ (СИ)
__eeput8_8, видимо, в сторонней либе хранится. То есть, вы смотрите на листинг только своего кода, а не всего, что включается в конечный hex-файл.
Вообще, мало верится, что при записи происходит проверка значения
Вообще, мало верится, что при записи происходит проверка значения
only pure true norwegian blackx 
Re: Вопросы по С/С++ (СИ)
А как сделать так, чтобы генерился полный листинг, который в т. ч. можно отлаживать в Протеусе?
Кстати, на аппаратном уровне как все это происходит? Есть ли внутри кристалла аппаратная проверка "нужно ли спускать/накачивать заряд в затворе полевиков?" или перед записью весь байт стирается?
Неужели разработчики компилятора поленились реализовать такую простейшую функцию? Ведь это пишется в 2 строчки! В чем смысл такого упущения?blackx писал(а):мало верится, что при записи происходит проверка значения
Кстати, на аппаратном уровне как все это происходит? Есть ли внутри кристалла аппаратная проверка "нужно ли спускать/накачивать заряд в затворе полевиков?" или перед записью весь байт стирается?
Re: Вопросы по С/С++ (СИ)
В малом смысле реализации такой проверки. EEPROM обычно используется для хранения каких-то редко изменяемых данных, например, настроек. Причем зачастую эти данные изменяются человеком. В таком режиме ресурс EEPROM чрезвычайно велик, и делать дополнительную защиту от записи уже существующего значения нет смысла.В чем смысл такого упущения?
Кроме того, данные в EEPROM постепенно деградируют, и выполняя запись того же значения, мы продлеваем срок его хранения, обновляя утекшую часть заряда. Но тут, в общем, речь опять же идет о десятках лет.
Нет. А во FLASH вообще стирается страница целиком, даже если меняем только один байт (остальные, естесственно, надо перписывать).Есть ли внутри кристалла аппаратная проверка
Разница между теорией и практикой на практике гораздо больше, чем в теории.
- Мikа
- Потрогал лапой паяльник
- Сообщения: 343
- Зарегистрирован: Пн апр 01, 2013 15:13:40
- Откуда: Москва
Re: Вопросы по С/С++ (СИ)
YS, подал идею по поводу переполнение таймера с разанее записанным в него числом, спс
Я продолжа.ю кавыряться с таймером. Опытным путём у меня напрашивается такой вывод:
Даже если мы не разрешаем прерывания, счётчики всёравно считают.
Всёравно переполняются\сравниваются с каким-то числом и т.п.
Как следствие поднимают флаг прерывания. Но ничего не происходит, т.к. прерывание не разрешено.
Но ка ктолько мы его разрешаем, оно тут же срабатывает, т.к. флаг был заранее поднят.
Поэтому при работе с прерыванием по совпадению счётчика с каким-то числом надо:
Сбросить флаг прерывания
Сбросить счётчик в 0
Разрешить прерывание по совпадению
Правильно? Оо
Даже если мы не разрешаем прерывания, счётчики всёравно считают.
Всёравно переполняются\сравниваются с каким-то числом и т.п.
Как следствие поднимают флаг прерывания. Но ничего не происходит, т.к. прерывание не разрешено.
Но ка ктолько мы его разрешаем, оно тут же срабатывает, т.к. флаг был заранее поднят.
Поэтому при работе с прерыванием по совпадению счётчика с каким-то числом надо:
Сбросить флаг прерывания
Сбросить счётчик в 0
Разрешить прерывание по совпадению
Правильно? Оо
Почему я здесь и задаю тупые вопросы?
Потому что хочу научиться.
Потому что хочу научиться.
Re: Вопросы по С/С++ (СИ)
А если кто-то безконца тыркает кнопки "погромче-потише", "поярче-потемнее" и т. п., а проц каждый раз пишет в ЭСППЗУ? Так и дотыркаться можно.YS писал(а):EEPROM обычно используется для хранения каких-то редко изменяемых данных, например, настроек.
Так программу в ПЗУ проца никто не обновляет в это время и дело закончится тем, что заряд скорее утечет в памяти прогамм, зато данные в ЭСППЗУ целые будут. Правда кому они будут нужны после этогоYS писал(а):выполняя запись того же значения, мы продлеваем срок его хранения, обновляя утекшую часть заряда
Ну это в памяти программ я так понял. А память данных ЭСППЗУ разве также шьется?YS писал(а):Нет. А во FLASH вообще стирается страница целиком, даже если меняем только один байт (остальные, естесственно, надо перписывать).
Re: Вопросы по С/С++ (СИ)
Давайте посчитаем. Ресурс EEPROM AVR - 100000 циклов перезаписи. Пускай человек тыкает кнопку раз в секунду по двенадцать часов в день, и при каждом тычке процессор сохраняет измененное значение в память.А если кто-то безконца тыркает кнопки
Итак, 100000 тычков-секунд. 27 часов тыкания. Почти три дня тыкания кнопки раз в секунду, двенадцать часов в день, без перерыва. Это кто-нибудь осилит?
Где как. У MSP430 так же, только размер сегмента меньше. У AVR побайтно. Но физически и память программ, и память данных используют один принцип - это один и тот же (в смысле технологии) FLASH. Только доступ к ячейкам организован по-разному, и EEPROM заточен под больший ресурс.А память данных ЭСППЗУ разве также шьется?
Ага, я сам так спотыкался.YS, подал идею по поводу переполнение таймера с разанее записанным в него числом, спс
Флаг сбрасывается автоматически при входе в обработчик. Вот если не хочется, чтобы после разрешения прерываний произошел переход в обработчик, тогда перед разрешением его надо сбросить.Поэтому при работе с прерыванием по совпадению счётчика с каким-то числом надо:
Сбросить флаг прерывания
Сбросить счётчик в 0
Разрешить прерывание по совпадению
Сбрасывать счетчик в ноль можно тогда, когда прерывание одно - для простоты. А вот если на одном таймере висит несколько временных интервалов по прерываниям, тогда в обработчике надо прибавить к соответствующему регистру совпадения число, соответствующее времени до следующего срабатывания. При этом получается, что переполнение также автоматом учитывается.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
-
srg320
- Встал на лапы
- Сообщения: 85
- Зарегистрирован: Пт фев 01, 2013 17:47:26
- Откуда: Украина, Луганская область
Re: Вопросы по С/С++ (СИ)
Здравствуйте!
Есть проект в IAR ARM, С и ассемблер вперемешку.
Есть, например, структура
есть макрос на С для вычисления смещения полей структуры
допустим напишем так
и TeStackLimit будет всегда равен реальному адресу поля StackLimit в структуре NT_TIB, даже если структура в будущем изменится.
Дальше, есть код на ассемблере
Вопрос: возможно ли и каким образом в ассеблерных файлах использовать дефайны из С, чтобы каждый раз не считать смещения полей, а написать, например, так
потому как такого кода будет много, и определения структур в будущем будут изменяться.
Отказаться от ассемблера и писать всё на С - не вариант. Заранее благодарен.
Есть проект в IAR ARM, С и ассемблер вперемешку.
Есть, например, структура
Спойлер
Код: Выделить всё
typedef struct _NT_TIB {
struct _EXCEPTION_REGISTRATION_RECORD* ExceptionList; // 00h
PVOID StackBase; // 04h
PVOID StackLimit; // 08h
....
struct _NT_TIB *Self; // 18h
} NT_TIB, *PNT_TIB;Код: Выделить всё
#define OFFSET(type, field) ((ULONG_PTR)(&((type *)0)->field))Код: Выделить всё
#define TeStackLimit OFFSET(NT_TIB, StackLimit)Дальше, есть код на ассемблере
Код: Выделить всё
LDR R0,[R2, #+0x08] ; R0 = [R2]->StackLimit, в R2 адрес переменной типа NT_TIBКод: Выделить всё
LDR R0,[R2, #+TeStackLimit]Отказаться от ассемблера и писать всё на С - не вариант. Заранее благодарен.


