Jump to content
Sign in to follow this  
mosfetx

Си для AVR. Пытаюсь разобраться в структуре кода.

Recommended Posts

Всем привет. Снова взялся за Си. Прошлые попытки провалились. Если не найду ответа в гугл или здесь, вопросы буду писать в эту тему

Вопрос в следующем.

#define F_CPU 8000000
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
	unsigned char i=0;
    DDRD = 0xFF;
	PORTD = 0x00;
    while (1) 
    {
		for ( i=0; i<=7; i++ )
		{
			PORTD = (1<<i);
			_delay_ms(500);
		}
		
		for ( i=0; i<=7; i++ )
		{
			PORTD = ~(1<<i);
			_delay_ms(500);
		}
		
    }
}

Во втором цикле for, как я понимаю должно быть так.в момент входа в цикл PORTD все биты нули. И при выполнении строки PORTD = ~(1<<i); ни чего не должно происходить.

так как запись нуля в ноль ни чего не произойдёт. Но как только доходит до этой строки все биты PORTD выставляются в единицы. И потом начинает тухнуть один светодиод с сдвигом влево.

Объясните пожалуйста почему так. Вроде это побитовые операции, 

 

Edited by mosfetx

Share this post


Link to post
Share on other sites
12 минут назад, mosfetx сказал:

Объясните пожалуйста почему так

i=1  PORTD = ~(1<<1)  в двоичном 00000001 сдвигаем на 1, получаем 00000010, побитово инвертируем, в порт пишется 11111101

i=12 PORTD = ~(1<<2)  в двоичном 00000001 сдвигаем на 2, получаем 00000100, инвертируем, в порт пишется 11111011

Ну и так далее. Так что все правильно работает, не трожь :) 

Share this post


Link to post
Share on other sites

То есть чтобы не происходило инвертирование всех битов мне надо писать PORTD &= ~(1<<i);?

Share this post


Link to post
Share on other sites

Руководство для разработчика приложений на базе STM32WB55

Представив двухъядерные беспроводные микроконтроллеры STM32WB для IoT-приложений, компания STMicroelectronics предлагает разработчикам экосистему, включающую в себя отладочные платы, примеры кода для микроконтроллера, готовое ПО всех уровней и большой массив документации.

Читать статью

мне кажется что здесь варианты:

1. бегущей тени

{

 PORTD = (1<<i);

_delay_ms(500);

PORTD=0;}

2.бегщий огонь

{

PORTD = ~(1<<i);

_delay_ms(500);

PORTD=0xFF;}

Share this post


Link to post
Share on other sites
                     

Контроль в спящем режиме: повышение КПД батарейного питания с помощью DC/DC MAX17225 nanoPower

В статье описан практический опыт разработчика, применившего повышающий DC/DC-преобразователь MAX17225. В результате ряда практических экспериментов, потребовавших существенного обновления технической базы компании-разработчика, автор убедительно доказывает преимущества выбранного компонента и схемотехнической реализации. Увеличенное на 50% время автономной работы лучше других аргументов говорит об эффективности конвертеров MAX17225, а также о важности предварительной оценки элементной базы.

Подробнее

24 минуты назад, mosfetx сказал:

То есть чтобы не происходило инвертирование всех битов мне надо писать PORTD &= ~(1<<i);?

Конструкция (1<<i) дает байт с 1 в бите с номером i.  Побитовое отрицание ~ дает байт с единицами и нулем в бите i.

Да, сброс одного бита i  PORTD = PORTD & ( ~(1<<i) )  или кратко  PORTD &= ~(1<<i)

Установка одного бита i  PORTD = PORT  |  (1<<i) или кратко PORTD | =  (1<<i)

Но в вашем коде тоже все правильно, сначала бежит 1 от 0 до7 бита, потом так же бежит 0 при остальных битах в единице.

Share this post


Link to post
Share on other sites
10 часов назад, mosfetx сказал:

for ( i=0; i<=7; i++ ) { PORTD = (1<<i); _delay_ms(500); }

Довольно неоптимальная конструкция, скорее всего компилятор для (1<<i) тоже организует цикл. Вот так гораздо лучше:

for(uint8_t i=1; i; i<<1){
  PORTD = i;
  _delay_ms(500);
}

 Соответственно, во втором варианте надо лишь инвертировать i перед вывoдом в порт: PORTD = ~i;

Share this post


Link to post
Share on other sites

Учу по урокам с этого сайта http://narodstream.ru/avr-urok-7-knopka/.

Встретил там такие предложения.

Цитата

Можно пойти на хитрость и применить вот такую конструкцию PINB&0b00000001.

Данная конструкция нам и проверит нулевой бит. То есть если в регистре PINB также будет 1 в нулевом его бите,

то независимо от состояния остальных битов в данном регистре мы получим ненулевой результат, что также является истиной.

Наверное он имел ввиду if(!(PINB&0b00000001)?

и ещё я вообще не понял что он тут имеет ввиду

Цитата

То есть если ни с чем не сравнивать в условии результат, то условие эквивалентно сравниванием с нулём, только наоборот

. Для истинности результат должен быть ненулевым — (результат!=0).

Возможно глупые вопросы но я должен все понимать чтоб двигаться дальше.

Share this post


Link to post
Share on other sites

Не знаю, что там за уроки, но правильно так: всё, что не ноль, эквивалентно истине. Поэтому (a) и (a != 0) абсолютно эквивалентны в качестве условия в if и других местах, где требуется.

Главное, не думать, что истина всегда эквивалентна 1.

То есть (PINB & 1) и (PINB & 2) совсем не то же самое, что (PINB & 1) == 1 и (PINB & 2) == 1

Share this post


Link to post
Share on other sites

Глупые вопросы продолжаются

#define F_CPU 8000000, #define F_CPU 8000000L, #define F_CPU 8000000UL

Зачем здесь эти буквы после 8000000.

Share this post


Link to post
Share on other sites

Во-первых, этой строчки не должно быть в тексте ваших исходников. Определение тактовой частоты должно задаваться в makefile или в свойствах проекта вцелом, а не в индивидуальных исходниках. В самом дико крайнем случае - в единственном заголовочном файле, подключаемым ко всем исходникам проекта, но и этот случай я бы не одобрил.

Во-вторых, суффикс UL означает, что число следует рассматривать, как unsigned long, а суффикс L - как просто long. Это необходимо потому, что в Си по умолчанию (т.е. без суффиксов) все числа имеют размерность int, а значит, бОльшее число туда может влезть не полностью, что приведет к загадочным результатам вычислений. В последних версиях (стандартов Си или компиляторов?) это вроде как уже немного скорректировано, но я бы на это не стал надеяться, и рекомендовл бы продолжать использовать суффиксы явно.

Edited by ARV

Share this post


Link to post
Share on other sites
05.12.2019 в 22:14, mosfetx сказал:

Вопрос в следующем.

Лучше всего вам создать консольный проект на компьютере и запустить эту вашу функцию в дебаге, закоментировав апаратнозависимые хидера и переопределив апаратнозависимые функции и переменные-регистры.Например так:

unsigned char PORTD ;

_delay_ms(short val)

{

printf("delay for %d ms, PORTD=0x%x;\n",val, PORTD);

}

На все вопросы вам ответит компилятор, все остальное от лукавого!

05.12.2019 в 22:14, mosfetx сказал:

Объясните пожалуйста почему так. Вроде это побитовые операции, 

unsigned char PORTD ;
void _delay_ms(short val) 
{ 
	printf("delay for %d ms, PORTD=0x%x;\n",val, PORTD); 
  static int debugCnt = 0;
  if(debugCnt++ > 20) exit(0);
}

во так без дебага можно посмотреть что с портом Д происходит на С-ях.

Share this post


Link to post
Share on other sites
2 часа назад, ARV сказал:

. Определение тактовой частоты должно задаваться в makefile или в свойствах проекта вцелом, а не в индивидуальных исходниках.

А зачем вообще в коде задавать значение тактовой ? что оно нам даст ? тактовая же определяется во фьюзах и задается при прошивке отдельно.

Share this post


Link to post
Share on other sites
27 минут назад, E_C_C сказал:

А зачем вообще в коде задавать значение тактовой ? что оно нам даст ?

значения констант для задержек, вы думаете, на основании чего считаются? Вообще все что связано с временем требует значение тактовой частоты.

Share this post


Link to post
Share on other sites
2 минуты назад, ruhi сказал:

вы думаете, на основании чего считаются?

Это понятно.Так же если нужно сделать одинаковые временные интервалы при переносе проекта на разные чипы , с разными тактовыми. Но вот в плане вопроса ТС , он ничего не портирует , код пишется под атмегу 8 с 8мгц тактовой , зачем нужен дефайн ? Не проще один раз посчитать значение делителя и значение таймера и записать их.

Share this post


Link to post
Share on other sites
59 минут назад, E_C_C сказал:

Не проще один раз посчитать значение делителя и значение таймера и записать их.

Проще или не проще - вопрос лично для меня не стоит. Правильнее или не правильнее - так я ставлю вопрос. И ответ на него дал. Писать код неправильно учиться не надо, усилий требует вырабатывание привычки писать код правильно.

В программировании любая простота обязательно оборачиавется проблемами: либо до какого-то события, либо после него: мы или мучаемся над изучением/осваиванием чего-либо, либо мучаемся потом, отлавливая ошибки. Какие проблемы решать лучше - каждый сам выбирает для себя.

Share this post


Link to post
Share on other sites
45 минут назад, ARV сказал:

усилий требует вырабатывание привычки писать код правильно.

И сразу возникает вопрос - каков критерий "правильного"  кода?

Оптимальность ,т.е .скорость выполнения и нетребовательность к ресурсам железа ? Удобство в понимании другими ? удобство в написании для себя ?, а может изящество , или изощренность в решении задачи ?

К примеру - операцию деления  на любую степень двойки можно заменить сдвигом , это будет быстрее , но не так очевидно. И каждый автор учебника или курса предлагает своё видение , говоря что именно так и правильно. 

в уроках "народ стрим" , на которые ссылается топикстартер, проект разбит на  библиотеки и содержит много дефайнов , да это удобно, для программиста . А для начинающего создает сложности,  т.к .  нет наглядности , разумеется это моё ИМХО и я ни разу не претендую на авторитетное мнение.  

Edited by E_C_C

Share this post


Link to post
Share on other sites

Даже ребенка в игре с кубиками учат, что при строительстве пирамидки снизу должны быть кубики побольше, а выше - поменьше. То есть объясняют порядок, которого следует придерживаться. Так и в программировании: если придерживаться порядка, то будет легче.

Разумеется, если руки не дрожат и есть опыт, можно построить пирамиду и наоборот6 снизу маленький и тонкий, а на нем огромная куча больших и толстых. Но все это развалится от малешего толчка. Так и в программировании: если делать как-нибудь, оно вполне может работать, и даже будет скорее всего работать, но буквально до первой попытки что-то изменить.

При программировании на Си вопрос оптимальности - надуманный вопрос. В огромном количестве случаев любая "оптимизация вручную" (пример с делением) наверняка в конечном итоге проиграет оптимизации, которую устроит компилятор. Но даже если это и не так - необходимости в столь тонкой оптимизации почти никогда не встречается в любительских проектах: производительность современных микроконтроллеров настолько высока, что экономить на делении, заменяя его сдвигами, нет никакого смысла.

А все непонятки и сложности от незнакомости. Любому начинающему приучиться делать свои проекты многофайловыми совсем не сложно, а пользы от этого в будущем будет много.

Есть большая и толстая книга:

71AE90J735L%5B1%5D.gif

или в переводе на русский

Alen_Golub__Verevka_dostatochnoj_dliny_c

Прочесть которую необходимо каждому, кто вознамерился заниматься программирвоанием хотя бы раз в неделю. Хорошо прочищает голову, освобождая от всяких вопросов типа "а нужно ли?".

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
Sign in to follow this  

  • Сообщения

    • Сложно точно сказать. У меня на клещах никакого обнуления нет. Наверное это не имеет значения. Достаточно плотно сомкнуть.  А, это Вы наверное имеете ввиду стереть из памяти прошлые показания?  Это еще проще. Сотрите и все.
    • Не понял мысли, почему не работает? Когда на управляющих контактах чуть больше 0.6V, светодиоды зажигаются и их яркость плавно нарастает пропорционально росту управляющего потенциала до 9.5V. После чего яркость не растёт, даже если подать от внешнего источника ещё большее напряжение.
    • — Мам, а что это дедушка весь день качается в своем кресле-качалке? — Да ему так легче рюмочку опрокидывать... 
    • Любит наш народ, всякое г-но... (С) Микроконтроллерное управление усилителем- хорошо. Микроконтроллерное управление Худом- лексус везет прицеп с навозом.  
    • Подскажите магнитола Pioneer AVH-X2550BT не работает сенсор и с пульта не реагирует на кнопки , причем не реагирует на все кроме BAND,MODE, SRC, . Сенсор менял , перепрошивал , в какую сторону смотреть ? 
    • Продам радиаторы охлаждения.
    • Привет всем! вот нашёл - делал терморегулятор для тёплого пола по "своей " технологии. В качестве "донора" использовал "ТВ" резетку чтоб всё в рамку вошло от серии W59.
×
×
  • Create New...