Си для микроконтроллеров и чайников. Часть 2. Операции с переменными и регистрами микроконтроллера.. Раздел: Начинающим.

Eugene's MCU

Среда, 25.06.2014, 21:52

Главная | | Мой профиль | Выход | RSS
Меню сайта
Категории каталога
Рекламный блок





Рекомендовать этот сайт:

Главная » Статьи » » Начинающим


Си для микроконтроллеров и чайников. Часть 2. Операции с переменными и регистрами микроконтроллера.
Краткое предисловие для начинающих: прочитать

§ > Обзор стандартных операций с регистрами.
  
      Настало время перейти к более серьёзным операциям над регистрами и программными переменными. Управление работой микроконтроллера в большинстве случаев сводится к следующему простому набору действий с его регистрами:
  
      1. Запись в регистр необходимого значения.
      2. Чтение значения регистра.
      3. Установка в единицу нужных разрядов регистра.
      4. Сброс разрядов регистра в ноль.
      5. Проверка разряда на логическую единицу или логический ноль.
      6. Изменение логического состояния разряда регистра на противоположное.
  
      Во всех указанных действиях принимает участие оператор присваивания языка Си, записываемый в виде знака равенства. Принцип действия оператора примитивно прост - он записывает в регистр или переменную расположенную слева от него, значение того, что записано справа. Справа может находится константа, другой регистр, переменная либо состоящее из них выражение, например:

      A = 16; // Присвоить переменной A значение 16;
      A = B; // Считать значение переменной B и присвоить это значение переменной A;
      A = B+10; // Считать значение переменной B, прибавить к считанному значению 10, результат присвоить переменной A (значение переменной B при этом не изменяется).
 
§ > Запись и чтение регистров.

      Из рассмотренных примеров видно, что оператор присваивания сам по себе решает две первые задачи — запись и чтение значений регистров. Например для отправки микроконтроллером AVR байта по шине UART достаточно записать его в передающий регистр с именем UDR:
   
  
     UDR = 8; // Отправить по UART число 8;
      
  
      Чтобы получить принятый по UART байт достаточно считать его из регистра UDR:
   
  
     A = UDR; // Считать принятый байт из UART и переписать в переменную A.
      
  
§ > Установка битов регистров.
 
      Язык Си не имеет в своём составе команд непосредственного сброса или установки разрядов переменной, однако присутствуют побитовые логические операции "И" и "ИЛИ", которые успешно используются для этих целей.
      Оператор побитовой логической операции "ИЛИ" записывается в виде вертикальной черты - "|" и может выполнятся между двумя переменными, а так же между переменной и константой. Напомню, что операция "ИЛИ" над двумя битами даёт в результате единичный бит, если хотя бы один из исходных битов находится с состоянии единицы. Таким образом для любого бита логическое "ИЛИ" с "1" даст в результате "1", независимо от состояния этого бита, а "ИЛИ" с логическим "0" оставит в результате состояние исходного бита без изменения. Это свойство позволяет использовать операцию "ИЛИ" для установки N-ого разряда в регистре. Для этого необходимо вычислить константу с единичным N-ным битом по формуле 2^N, которая называется битовой маской и выполнить логическое "ИЛИ" между ней и регистром, например для установки бита №7 в регистре SREG:

      (SREG | 128) — это выражение считывает регистр SREG и устанавливает в считанном значении седьмой бит, далее достаточно изменённое значение снова поместить в регистр SREG:
   
  
      SREG = SREG | 128; // Установить бит №7 регистра SREG.
      
 
      Такую работу с регистром принято называть "чтение - модификация - запись", в отличие от простого присваивания она сохраняет состояние остальных битов без именения.
      Приведённый программный код, устанавливая седьмой бит в регистре SREG, выполняет вполне осмысленную работу - разрешает микроконтроллеру обработку программных прерываний. Единственный недостаток такой записи — в константе 128 не легко угадать установленный седьмой бит, поэтому чаще маску для N-ного бита записывают в следующем виде:

      (1<<N) - это выражение на языке Си означает, число один, сдвинутое на N разрядов влево, это и есть маска с установленным N-ным битом. Тогда предыдущий код в более читабельном виде:
 
  
     SREG = SREG | (1<<7);
      
  
      или ещё проще с использование краткой формы записи языка Си:
 
  
     SREG |= (1<<7);
      
  
      которая означает - взять содержимое справа от знака равенства, выполнить между ним и регистром слева операцию, стоящую перед знаком равенства и записать результат в регистр или переменную слева.
  
§ > Сброс битов в регистрах.
 
      Ещё одна логическая операция языка Си – побитовое "И", записывается в виде символа "&". Как известно, операция логического "И", применительно к двум битам даёт единицу тогда и только тогда, когда оба исходных бита имеют единичное значение, это позволяет применять её для сброса разрядов в регистрах. При этом используется битовая маска, в которой все разряды единичные, кроме нулевого на позиции сбрасываемого. Её легко получить из маски с установленным N-ным битом, применив к ней операцию побитного инвертирования:
      ~(1<<N) в этом выражении символ "~" означает смену логического состояния всех битов маски на противоположные. Так, например, если (1<<3) в двоичном представлении – 00001000b,  то ~(1<<3) уже 11110111b. Сброс седьмого бита в регистре SREG будет выглядеть так:
 
  
     SREG = SREG & (~ (1<<7));  или кратко: SREG &= ~ (1<<7);
      
         
     В упомянутом ранее заголовочном файле для конкретного микроконтроллера приведены стандартные имена разрядов регистров специального назначения, например:
 
  
     #define OCIE0 1
      
    
     здесь #define – указание компилятору заменять в тексте программы сочетание символов "OCIE0" на число 1, то есть стандартное имя бита OCIE0, который входит в состав регистра TIMSK микроконтроллера Atmega64 на его порядковый номер в этом регистре. Благодаря этому установку бита OCIE0 в регистре TIMSK можно нагляднее записывать так:
 
  
     TIMSK|=(1<<OCIE0);
      
    
     Устанавливать или сбрасывать несколько разрядов регистра одновременно можно, объединяя битовые маски в выражениях оператором логического "ИЛИ":
 
  
     PORTA |= (1<<1)|(1<<4); // Установить выводы 1 и 4 порта A в единицу;
     PORTA&=~((1<<2)|(1<<3)); // Выводы 2 и 3 порта A сбросить в ноль.
      
    
§ > Проверка разрядов регистра на ноль и единицу.
 
     Регистры специального назначения микроконтроллеров содержат в своём составе множество битов-признаков, так называемых "флагов”, уведомляющих программу о текущем состоянии микроконтроллера и его отдельных модулей. Проверка логического уровня флага сводится к подбору выражения, которое становится истинным или ложным в зависимости от того установлен или сброшен данный разряд в регистре. Таким выражением может служить логическое "И” между регистром и маской с установленным разрядом N на позиции проверяемого бита :

     (REGISTR & (1<<N)) в этом выражении операция "И” во всех разрядах кроме N-ного даст нулевые значения, а проверяемый разряд оставит без изменения. Таким образом возможное значения выражения будут или 0 или 2^N, например для второго бита регистра SREG:

     

     Приведённое выражение можно использовать в условном операторе if (выражение) или операторе цикла while (выражение), которые относятся к группе логических, то есть воспринимают в качестве аргументов значения типа истина и ложь. Поскольку язык Си, приводя числовые значения к логическим, любые числа не равные нулю воспринимает как логическую истину, значение (REGISTR & (1<<N)) равное 2^N в случае установленного бита, будет воспринято как "истина".
     Если появляется необходимость при установленном бите N получить для нашего выражения логическое значение «ложь», достаточно дополнить его оператором логической инверсии в виде восклицательного знака - !(REGISTR & (1<<N)). Не следует путать его с похожим оператором побитовой инверсии (~) меняющим состояние битов разряда на противоположное. Логическая инверсия работает не с числовыми значениями, а с логическими, то есть преобразует истинное в ложное и наоборот. Такая конструкция приводится в DataSheet на Atmega как пример для ожидания установки бита UDRE в регистре UCSRA, после которого можно отправлять данные в UART:
  
  
     while ( !( UCSRA & (1<<UDRE)) ) { } // Ждать установки UDRE.
      
    
    Здесь при сброшенном бите UDRE выражение ( UCSRA & (1<<UDRE)) даст значение ”ложь”, инвертированное
!( UCSRA & (1<<UDRE)) — ”истину”, и пока это так, программа будет выполнять действия внутри фигурных скобок, то есть не делать ничего (стоять на месте). Как только бит UDRE установится в единицу, программа перейдёт к выполнению действий следующих за конструкцией while(), например займётся отправкой данных в UART.
 
§ > Изменение состояния бита регистра на противоположное.
   
     Эту, с позволения сказать, проблему с успехом решает логическая операция побитного "ИСКЛЮЧАЮЩЕГО ИЛИ” и соответствующий ей оператор Си, записываемый в виде символа " ^ ”. Правило "исключающего или" с двумя битами даёт "истину” тогда и только тогда, когда один из битов установлен, а другой сброшен. Не трудно убедиться, что этот оператор, применённый между битовой маской и регистром, скопирует в результат биты стоящие напротив нулевых битов маски без изменения и инвертирует расположенные напротив единичных. Например, если: reg=b0001 0110 и mask=b0000 1111, то reg^mask=b0001 1001. Таким способом можно менять состояние светодиода, подключенного к пятому биту порта A:
  
  
     #define LED 5 // Заменять в программе сочетание символов LED на число 5 (вывод светодиода).
     …
     PORTA ^=(1<< LED); // Погасить светодиод, если он светится и наоборот.
      
   
§ > Арифметика и логика языка Си.  

     Мы рассмотрели типичный набор операций, используемый при работе с регистрами микроконтроллера. Помимо них в арсенале языка имеется ряд простейших арифметических и логических операций, описания которых можно найти в любом справочнике по Си, например: 
  
     
 
     Для более подробного знакомства с операциями над переменными и языком Си в целом, рекомендую книгу "Язык программирования Си" Б. Керниган, Д. Ритчи.
   
   


При использовании материалов сайта ссылка на данный источник обязательна.

Категория: Начинающим | Добавил: eugenemcu (24.10.2009) | Автор:

Просмотров: 47285 | Комментарии: 9 | Рейтинг: 4.9/19 |
Всего комментариев: 9
0 Спам
* 1 (19.02.2010 15:47) [Материал]
мужик огромный респект за такое разжевывание, только начал изучать си - перво появившиеся вопросы прям на странице все разом спасибо огромное!
асемблер знаю в идеале но блин cbirf это нечто...

0 Спам
* 2 (12.03.2010 13:00) [Материал]
Большое Спасибо!!!

0 Спам
* 3 (02.08.2010 14:32) [Материал]
Классное описание. По долгу службы пришлось столкнуться с контроллерами, а вот как к ним подступиться не знаю, очень помогает. Спасибо.

0 Спам
* 4 (28.10.2010 03:38) [Материал]
наконец становится все понятней...
только вот чтоб переслать число по uart нужно поместить его в регистр.
а если данные в мк поступают быстрее чем пересылается это число? как узнать что оно еще не отправилось?

0 Спам
* 5 (28.10.2010 04:43) [Материал]
нашел ответ в вашей же след. статье...
жду о подключении быстрого внешнего ацп к мк с "кучей" мультиплексоров!

0 Спам
* 6 (30.01.2011 20:36) [Материал]
Дружище, огромное тебе спасибо за статью! Знатная вещь, была масса вопросов но решил их прочитав статью, супер!

0 Спам
* 7 (22.02.2011 19:02) [Материал]
Благодарю за статью, раьнше занимался только схемотехникой, а теперь пришлось и код писать на STM. Думал все капец уволняться надо))) а тут наткнулся на статью. Ты молодец, доброе дело кидаешь в массы!!!

С праздником мужики!!! С 23 февраля


0 Спам
* 8 (02.05.2011 12:37) [Материал]
Как под копирку! Слово в слово согласен со всеми остальными.
Особенно после мучений со SRAMом.

0 Спам
* 9 (05.05.2011 16:03) [Материал]
Спаибо за понятность.

Статистика

Наш магазин




Какую среду разработки Вы используете?

[ Результаты · Архив опросов ]
Всего ответов: 1545



Им нужна Ваша помощь: