AVR123:Глава 5 — различия между версиями

Материал из roboforum.ru Wiki
Перейти к: навигация, поиск
 
(не показаны 3 промежуточные версии этого же участника)
Строка 15: Строка 15:
 
Эта программа не делает ни чего полезного — но это уже программа и она показывает что в программе на языке Си — должна быть главная функция main — обязательно !
 
Эта программа не делает ни чего полезного — но это уже программа и она показывает что в программе на языке Си — должна быть главная функция main — обязательно !
  
Скачайте и Распечатайте.'''[[http://avr123.nm.ru/csyntax.pdf Памятка Си для МК на ОДНОЙ странице.]'''
+
Скачайте и Распечатайте.'''[http://avr123.nm.ru/csyntax.pdf Памятка Си для МК на ОДНОЙ странице.]'''
  
 
Рассказывая про МК я говорил вам, что:
 
Рассказывая про МК я говорил вам, что:
Строка 589: Строка 589:
 
[[http://avr123.nm.ru/ascii.pdf Скачайте и распечатайте таблицу символов ASCII на ОДНОЙ странице!]
 
[[http://avr123.nm.ru/ascii.pdf Скачайте и распечатайте таблицу символов ASCII на ОДНОЙ странице!]
  
==ОГЛАВЛЕНИЕ==
+
9)      goto  - оператор безусловного (немедленного) перехода. 
[http://www.citforum.ru/programming/c/h11.shtml  1.ОПИСАНИЕ ЯЗЫКА СИ]
+
<source lang="C">
 +
... какой-то код нашей программы на Си ...
  
[http://www.citforum.ru/programming/c/h11.shtml#11  1.1. ЭЛЕМЕНТЫ ЯЗЫКА СИ]
+
mesto_5: /* сюда мы попадем после выполнения строки программы goto mesto_5  */  
 +
    код будет выполнятся после goto mesto_5;
  
[http://www.citforum.ru/programming/c/h11.shtml#111  1.1.1. Используемые символы]
+
... какой-то код нашей программы на Си ...
  
[http://www.citforum.ru/programming/c/h11.shtml#112  1.1.2. Константы]
+
mesto_1: /* сюда мы попадем после выполнения строки программы goto mesto_1  */
 +
    код будет выполнятся после goto mesto_1;
  
[http://www.citforum.ru/programming/c/h11.shtml#113  1.1.3. Идентификатор]
+
... какой-то код нашей программы на Си ...
  
[http://www.citforum.ru/programming/c/h11.shtml#114  1.1.4. Ключевые слова]
+
goto mesto_1; /* перейти в то место программы где в начале строки написано mesto_1:     */
  
[http://www.citforum.ru/programming/c/h11.shtml#115  1.1.5. Использование комментариев в тексте программы]
+
... какой-то код нашей программы на Си ...
  
[http://www.citforum.ru/programming/c/h12.shtml#12  1.2. ТИПЫ ДАННЫХ И ИХ ОБ ЯВЛЕНИЕ]
+
goto mesto_5; /* перейти в то место программы где в начале строки написано mesto_5:     */
  
[http://www.citforum.ru/programming/c/h12.shtml#121  1.2.1  Категории типов данных]
+
... какой-то код нашей программы на Си ...
 +
</source>
 +
 +
  
[http://www.citforum.ru/programming/c/h12.shtml#122  1.2.2. Целый тип данных]
 
  
[http://www.citforum.ru/programming/c/h12.shtml#123  1.2.3. Данные плавающего типа]
 
  
[http://www.citforum.ru/programming/c/h12.shtml#124 1.2.4. Указатели]
+
Используйте goto с осторожностью! Думайте к чему может привести выполнение функций или конструкций вашей программы не до конца.  
  
[http://www.citforum.ru/programming/c/h12.shtml#125 1.2.5. Переменные перечислимого типа]
+
CVAVR помогает вам в контроле не позволяя где угодно втыкать goto
  
[http://www.citforum.ru/programming/c/h12.shtml#126  1.2.6. Массивы]
+
 
 +
Оператор Си  ?  работает почти как  if - вот так:  
  
[http://www.citforum.ru/programming/c/h12.shtml#127  1.2.7. Структуры]
+
Пример функция в которую передается значение переменной val_d
  
[http://www.citforum.ru/programming/c/h12.shtml#128  1.2.8. Объединения (смеси)]
+
Вызов функции и передач в нее числа хранящегося в переменной с именем peremennaya
  
[http://www.citforum.ru/programming/c/h12.shtml#129  1.2.9. Поля битов]
+
resultat = funkziya(peremennaya);
  
[http://www.citforum.ru/programming/c/h12.shtml#1210 1.2.10.  Переменные с изменяемой структурой]
+
   
  
[http://www.citforum.ru/programming/c/h12.shtml#1211 1.2.11. Определение объектов и типов]
+
В функции число из peremennaya будет помещено в val_d и обработано.
  
[http://www.citforum.ru/programming/c/h12.shtml#1212  1.2.12.  Инициализация данных]
+
int funkziya(int val_d)
 +
{
 +
  return ((val_d>511)?(-1024+val_d):(val_d));
 +
}
  
[http://www.citforum.ru/programming/c/h13.shtml#13  1.3.  ВЫРАЖЕНИЯ И ПРИСВАИВАНИЯ]
+
( (выражение) ? ( если выражение истина ) : ( если выражение ложно ) )
  
[http://www.citforum.ru/programming/c/h13.shtml#131  1.3.1.  Операнды и операции]
+
если val_d>511 то функция возвратит val_d уменьшенное на 1024
  
[http://www.citforum.ru/programming/c/h13.shtml#132  1.3.2.  Преобразования при вычислении выражений]
+
если val_d=<511 то функция возвратит val_d не меняя его.
  
[http://www.citforum.ru/programming/c/h13.shtml#133 1.3.3. Операции отрицания и дополнения]
+
Возвращаемое функцией значение val_d будет помещено в переменную в строке вызова функции - resultat
  
[http://www.citforum.ru/programming/c/h13.shtml#134  1.3.4Операции разадресации и адреса]
+
Подробнее о функциях будет написано ниже.  
 +
  
[http://www.citforum.ru/programming/c/h13.shtml#135  1.3.5.  Операция sizeof]
+
Ну вот - ПОЧТИ
 +
всё что нужно нам из Си !
  
[http://www.citforum.ru/programming/c/h13.shtml#136  1.3.6.  Мультипликативные операции]
 
  
[http://www.citforum.ru/programming/c/h13.shtml#137  1.3.7.  Аддитивные операции]
+
Как использовать описанное выше вы можете
 +
посмотреть в примерах к компилятору !
  
[http://www.citforum.ru/programming/c/h13.shtml#138  1.3.8.  Операции сдвига]
+
Примеры в папке :
  
[http://www.citforum.ru/programming/c/h13.shtml#139  1.3.9.  Поразрядные операции]
+
C:\CVAVR\EXAMPLES
  
[http://www.citforum.ru/programming/c/h13.shtml#1310 1.3.10.  Логические операции]
+
Открывайте файлы  исходников .с  и разбирайте текст программ -
 +
что делает каждая строчка кода !
  
{{AttentionBlock|правильно вот так:  Операция логического И вырабатывает значение 1 если оба операнда имеют НЕ нулевые значения.|Я обнаружил ошибку в разделе 1.3.10}}                 
+
Это великолепный способ
[http://www.citforum.ru/programming/c/h13.shtml#1311  1.3.11.  Операция последовательного вычисления]
+
само-обучения программированию !
  
[http://www.citforum.ru/programming/c/h13.shtml#1312  1.3.12.  Условная операция]
+
Новичку понадобятся для понимания программ написанных профи :
  
[http://www.citforum.ru/programming/c/h13.shtml#1313 1.3.13Операции увеличения и уменьшения]
+
Указатели, Структуры и Союзы.   
  
[http://www.citforum.ru/programming/c/h13.shtml#1314 1.3.14Простое присваивание]
+
Прочитайте о них в он-лайн книгах по Си которые расположены ниже на страничке. Примеры применения указателей, структур и союзов в разных компиляторах вы найдете в FAQ к курсу по AVR - скачайте и читайте.
 +
 
 +
==Структура  программы на  языке  Си.==
 +
 
 +
Программа на языке Си это текстовый файл, обычно с расширением .c
 +
 
 +
Текст программы называют исходным или "исходником" или "сурцом"
 +
от анг. source code - это вам ключевые слова для поиска
 +
 
 +
Весь исполняемый код программы на Си находится в функциях -
 +
т.е. в фигурных  скобках  {  исполняемый  код  программы  }
 +
 
 +
   
  
[http://www.citforum.ru/programming/c/h13.shtml#1315  1.3.15.  Составное присваивание]
+
===Программа на Си имеет определенную структуру :===
  
[http://www.citforum.ru/programming/c/h13.shtml#1316  1.3.16.  Приоритеты операций и порядок вычислений]
+
1) заголовок
  
[http://www.citforum.ru/programming/c/h13.shtml#1317 1.3.17. Побочные эффекты]
+
2) включение необходимых внешних файлов - #include
  
[http://www.citforum.ru/programming/c/h13.shtml#1318 1.3.18. Преобразование типов]
+
3) ваши определения для удобства работы - #define
  
[http://www.citforum.ru/programming/c/h14.shtml#14  1.4.  ОПЕРАТОРЫ]
+
4) объявление глобальных переменных и констант
  
[http://www.citforum.ru/programming/c/h14.shtml#141  1.4.1.  Оператор выражение]
+
    Глобальные переменные и константы 
  
[http://www.citforum.ru/programming/c/h14.shtml#142 1.4.2. Пустой оператор]
+
- объявляются вне какой либо функции.   
 +
    т.е. не после фигурной скобки  {
  
[http://www.citforum.ru/programming/c/h14.shtml#143  1.4.3.  Составной оператор]
+
- доступны в любом месте программы - значит можно читать их значения и присваивать переменным значения там где вам требуется - в любом месте программы после их объявления.  
  
[http://www.citforum.ru/programming/c/h14.shtml#144  1.4.4.  Оператор if]
+
5) описание функций - обработчиков прерываний
  
[http://www.citforum.ru/programming/c/h14.shtml#145 1.4.5.  Оператор switch]
+
6) описание других функций используемых в программе
  
[http://www.citforum.ru/programming/c/h14.shtml#146 1.4.6.  Оператор break]
+
7) функция main        <-  это единственный обязательный пункт !
  
[http://www.citforum.ru/programming/c/h14.shtml#147  1.4.7.  Оператор for]
+
 
 +
 +
Это не жесткий порядок а ориентировочный !
  
[http://www.citforum.ru/programming/c/h14.shtml#148  1.4.8.  Оператор while]
+
Иногда п.6 это прототипы функций, а сами функции
 +
описываются полностью после п.7
  
[http://www.citforum.ru/programming/c/h14.shtml#149  1.4.9Оператор do while]
+
Прототип функции - показывает образец того как применять функцию в программе, какие значения в нее передаются и если она возвращает какое-то значение то прототип указывает тип возвращаемых данных. Прототип не имеет скобок {    } а после скобок (  ) ставится  ;
  
[http://www.citforum.ru/programming/c/h14.shtml#1410 1.4.10.  Оператор continue]
+
Функция - имеет { "тело" } в фигурных скобках. Тело это код на Си определяющий то что делает функция.  
  
[http://www.citforum.ru/programming/c/h14.shtml#1411  1.4.11.  Оператор return]
+
; после вызова функции не ставится !
  
[http://www.citforum.ru/programming/c/h14.shtml#1412  1.4.12.  Оператор goto]
+
Программа на Си начинает работу с функции  main()
  
[http://www.citforum.ru/programming/c/h15.shtml#15  1.5.  ФУНКЦИИ]
+
по необходимости из main()вызываются другие функции программы, из которых может быть вызов следующих функций, по завершении работы функции программа возвращается по той же цепочке как вызывались функции.  
 +
<source lang="C">
 +
main(){
  
[http://www.citforum.ru/programming/c/h15.shtml#151  1.5.1.   Определение и вызов функций]
+
... какой то код программы ...
  
[http://www.citforum.ru/programming/c/h15.shtml#152  1.5.2.  Вызов функции с переменным числом параметров]
+
вызов функции_1; //программа перейдет в функцию_1
  
[http://www.citforum.ru/programming/c/h15.shtml#153  1.5.3.  Передача параметров функции main]
+
строка программы; // будет выполнятся после
 +
                  // возврата из функции_1
  
[http://www.citforum.ru/programming/c/h16.shtml#16  1.6.   СТРУКТУРА ПРОГРАММЫ И КЛАССЫ ПАМЯТИ]
+
... какой то код программы ...
  
[http://www.citforum.ru/programming/c/h16.shtml#161 1.6.1.  Исходные файлы и объявление переменных]
+
}
 +
</source>
 +
На странице  3. "Прерывания в AVR"  - вы уже читали, что описанный выше ход программы может нарушаться прерываниями.
  
[http://www.citforum.ru/programming/c/h16.shtml#162 1.6.2.  Объявления функций]
+
   
  
[http://www.citforum.ru/programming/c/h16.shtml#163  1.6.3.  Время жизни и область видимости программных объектов]
 
  
[http://www.citforum.ru/programming/c/h16.shtml#164  1.6.4.  Инициализация глобальных и локальных переменных]
 
  
[http://www.citforum.ru/programming/c/h17.shtml#17  1.7.  УКАЗАТЕЛИ И АДРЕСНАЯ АРИФМЕТИКА]
 
  
[http://www.citforum.ru/programming/c/h17.shtml#171 1.7.1.  Методы доступа к элементам массивов]
+
==Пример программы на Си==  
  
[http://www.citforum.ru/programming/c/h17.shtml#172 1.7.2.  Указатели на многомерные массивы]
+
с описанной выше структурой я буду писать на голубом фоне.  
  
[http://www.citforum.ru/programming/c/h17.shtml#173  1.7.3.  Операции с указателями]
+
По мере надобности я буду разрывать голубой фон обычным текстом,
 +
затем голубой фон и программа будет продолжаться.  
  
[http://www.citforum.ru/programming/c/h17.shtml#174  1.7.4.  Массивы указателей]
+
Ниже будет написан пример ОДНОЙ программы на Си.  
  
[http://www.citforum.ru/programming/c/h17.shtml#175  1.7.5.   Динамическое размещение массивов]
+
<source lang="C"> 
 +
/* пункт заголовок программы
  
[http://www.citforum.ru/programming/c/h18.shtml#18  1.8.  ДИРЕКТИВЫ ПРЕПРОЦЕССОРА]
+
Он оформляется как комментарий, и обычно содержит информацию
  
[http://www.citforum.ru/programming/c/h18.shtml#181  1.8.1.  Директива #include]
+
- о названии, назначении, версии и авторе программы
 +
- краткое описание алгоритма программы
 +
- пояснения о назначении выводов МК и режиме его работы, фьюзы
 +
- компилятор, инструменты и их версии
 +
- другие сведения которые вы считает полезным указать
 +
 +
*/
  
[http://www.citforum.ru/programming/c/h18.shtml#182  1.8.2.  Директива #define]
+
// комментарий после двух косых черт пишут в одну строку!
  
[http://www.citforum.ru/programming/c/h18.shtml#183 1.8.3.  Директива #undef]
+
   
  
[http://www.citforum.ru/programming/c/h21.shtml#2  2.   ОРГАНИЗАЦИЯ СПИСКОВ И ИХ ОБРАБОТКА]
+
// пункт включение внешних файлов
  
[http://www.citforum.ru/programming/c/h21.shtml#21  2.1.   ЛИНЕЙНЫЕ СПИСКИ]
+
#include <mega16.h> /* перед компиляцией, препроцессор компилятора вставит вместо этой строчки содержимое (текст) заголовочного файла "хидера" mega16.h - этот файл содержит перечень регистров имеющихся в МК ATmega16 и соответствие их названий их физическим адресам в МК.
  
[http://www.citforum.ru/programming/c/h21.shtml#211  2.1.1.  Методы организации и хранения линейных списков]
+
Посмотрите его содержание !!!
  
[http://www.citforum.ru/programming/c/h21.shtml#212  2.1.2.  Операции со списками при последовательном хранении]
+
CVAVR\inc\mega16.h         
  
[http://www.citforum.ru/programming/c/h21.shtml#213  2.1.3.  Операции со списками при связном хранении]
+
Не забывайте указать какой МК вы используете в свойствах проекта в компиляторе  */
  
[http://www.citforum.ru/programming/c/h21.shtml#214  2.1.4.  Организация двусвязных списков]
 
  
[http://www.citforum.ru/programming/c/h21.shtml#215  2.1.5.   Стеки и очереди]
+
//delay functions
 +
#include <delay.h>
 +
/* перед компиляцией, препроцессор компилятора вставит вместо этой строчки текст "хидера" delay.h - этот файл содержит функции для создания пауз в программе.
  
[http://www.citforum.ru/programming/c/h21.shtml#216  2.1.6.  Сжатое и индексное хранение линейных списков]
+
Теперь чтобы сделать паузу вам нужно лишь написать :   */
 +
 +
delay_us(N); /* сделать паузу N (число) микроСек
 +
это должна быть константа - НЕ переменная !!!
 +
например delay_us(12 + 7*3);
 +
например delay_us(117);          */
  
[http://www.citforum.ru/programming/c/h22.shtml#22 2.2.    СОРТИРОВКА И СЛИЯНИЕ СПИСКОВ]
+
delay_ms(x); /* сделать паузу x милиСек
 +
x - может быть переменная, выражение или число
 +
от 0 до 65535 (тип unsigned int) 
 +
например delay_ms(3280);
 +
например delay_ms(переменная); 
 +
например delay_ms(переменная*4 + 760);  */
 +
   
  
[http://www.citforum.ru/programming/c/h22.shtml#221  2.2.1.  Пузырьковая сортировка]
+
// пункт 3    определения пользователя
  
[http://www.citforum.ru/programming/c/h22.shtml#222  2.2.2.   Сортировка вставкой]
+
// AD7896 control signals PORTB bit allocation
 +
#define ADC_BUSY PINB.0
 +
#define NCONVST PORTB.1
 +
/* после этих двух строк, перед компиляцией, препроцессор компилятора заменит в тексте программы ADC_BUSY на PINB.0 и NCONVST на PORTB.1
 +
<source lang="C">
 +
Таким образом вместо того что бы помнить что вывод занятости AD7896 подключен у вас к ножке PB0 вы можете проверять значение осмысленного понятия ADC_BUSY - "АЦП занят"
  
[http://www.citforum.ru/programming/c/h22.shtml#223  2.2.3.   Сортировка посредством выбора]
+
а вместо управления абстрактной ножкой PB1 (через PORTB.1) вы можете управлять "НьюКонвешнСтат" - NCONVST - "стартовать новое АЦ преобразование"
 +
<source lang="C">
 +
#define  -  Это  удобно !  Но ВОВСЕ не обязательно.   
 +
*/
 +
#define INIT_TIMER0 TCNT0=0x100L-F_XTAL/64L/500L
 +
/* этот пример показывает что определения могут быть и сложней !  */
 +
</source>
 +
 +
#define - может содержать и некоторые переменные, вместо которых в тексте программы могут быть подставлены и числа и слова. Может определять даже сложные, полноценные функции.  
  
[http://www.citforum.ru/programming/c/h22.shtml#224  2.2.4.  Слияние списков]
+
Например:  
  
[http://www.citforum.ru/programming/c/h22.shtml#225  2.2.5.  Сортировка списков путем слияния]
+
#define invbit(p,n) (p=p^bit(n))
  
[http://www.citforum.ru/programming/c/h22.shtml#226 2.2.6.  Быстрая и распределяющая сортировки]
+
Здесь переменные величины это 'p' и 'n'Теперь для инвертирования бита 5 в регистре PORTB вам достаточно написать в программе:
  
[http://www.citforum.ru/programming/c/h23.shtml#23  2.3.    ПОИСК И ВЫБОР В ЛИНЕЙНЫХ СПИСКАХ]
+
invbit(PORTB,5);
  
[http://www.citforum.ru/programming/c/h23.shtml#231  2.3.1.  Последовательный поиск]
+
Кроме того в самой правой части эти переменные величины могут быть связаны и арифметическими операциями и таких переменных может быть много.
  
[http://www.citforum.ru/programming/c/h23.shtml#232  2.3.2.   Бинарный поиск]
+
Примеры #define есть в FAQ к курсу.
  
[http://www.citforum.ru/programming/c/h23.shtml#233  2.3.3. М-блочный поиск]
+
Определения БИТ-ов AVR (соответствие номера бита в регистре его названию по ДШ) есть в "хидерах"  .h  в компиляторах ICC, IAR, WinAVR и других компиляторах,
  
[http://www.citforum.ru/programming/c/h23.shtml#234 2.3.4.  Методы вычисления адреса]
+
Но их нет в хидерах CodeVisionAVR  - это не позволяет напрямую вставлять в текст программы примеры кода из даташит МК
  
[http://www.citforum.ru/programming/c/h23.shtml#235 2.3.5.  Выбор в линейных списках]
+
Поэтому я сделал для вас файл - заголовок  m8_128.h содержащий определения битов некоторых AVR.
  
[http://www.citforum.ru/programming/c/h24.shtml 2.4.  РЕКУРСИЯ ]
+
Скачайте его и добавьте в программу вот так:   
  
[http://www.citforum.ru/programming/c/h11.shtml  Чтение по порядку глав]
+
(Если вы читаете курс с начала и делаете то, что предлагается то этот файл у вас уже есть).
 +
<source lang="C">
 +
#include <mega16.h>
 +
/* сперва обычный "хидер"-заголовок для МК
 +
  используемого в вашей программе */
  
Вообще сайт [http://www.citforum.ru/programming/c.shtml  СитФорум] по программированию ПК рулит!
+
#include <m8_128.h>
 +
/* затем мой "хидер"-заголовок с определениями
 +
  названий и номеров битов для используемого МК */
 +
</source>
  
 +
Теперь вы можете использовать примеры
 +
на Си из ДШ на ваш МК !
  
==Оглавление==
+
Мой файл  m8 128.h содержит определения битов для микроконтроллеров
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/preface/ Предисловие]
+
ATmega8  ATmega16  ATmega32  ATmega64  ATmega128
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/preface/#preface_to_1st  Предисловие к первому изданию ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/intro/  Введение ]
+
Для всех AVR определения битов есть в .h заголовках  WinAVR 
 +
вот архив  (127 Кб) скачайте и используйте если понадобится.  
 +
 +
 +
Мастер начального кода программы в компиляторе
 +
ICC умеет по вашему желанию автоматически делать
 +
#define для ножек для ножек МК !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/list_error/  Список ошибок, допущенных в книгеhr ]
+
Подробней про это и с картинкой смотри в соответствующей
 +
задаче курса.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/  Глава 1. Обзор языка]
+
Пункт 4.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p11  1.1 Начнем, пожалуй ]
+
==Объявление  переменных==
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p12  1.2 Переменные и арифметические выражения ]
+
Перед использованием переменной в программе
 +
на Си  её  необходимо объявить - т.е. указать компилятору
 +
какой тип данных она может хранить и как она называется.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p13  1.3 Инструкция for ]
+
Наиболее подробно об этом по ссылке:
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p14  1.4 Именованные константы ]
+
1.2. ТИПЫ ДАННЫХ И ИХ ОБ ЯВЛЕНИЕ
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p15  1.5 Ввод-вывод символов ]
+
Ниже сжато - самое главное:
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p151   1.5.1 Копирование файла ]
+
Формат объявления переменной таков:
 +
 
 +
[<storage modifier>] <type definition> <identifier>;
 +
 
 +
 
 +
;[<storage modifier>]:- необязательный элемент,
 +
он нужен толон нужен только в некоторых случаях и может быть:
 +
;extern :- если переменная может использоваться в других файлах исходного кода программы, например объявляется во внешнем файле - хидере  delay.h  приведенном выше, а используется в основном файле программы.
 +
;volatile :- ставьте если нужно предотвратить возможность повреждения содержимого переменной в прерывании, и не позволить компилятору попытаться выкинуть её при оптимизации кода.
 +
Ставьте всегда если не знаете точно - нужно или нет !    
 +
====пример:====
 +
volatile unsigned char x;
 +
 
 +
 
 +
;static :- если переменная локальная т.е. объявлена в какой либо функции после скобки {      и должна сохранять свое значение до следующего вызова этой функции.
 +
;register :- разместить переменную в регистрах AVR  - это может ускорить доступ к ней.  CVAVR по-умолчанию размещает переменные в регистрах до их заполнения.  Но размещение переменных в регистрах делает их не видимыми при отладке в PROTEUS.
 +
;eeprom :- разместить переменную в EEPROM. Это энергонезависимая память - значение таких переменных сохраняется при выключении питания и при перезагрузке МК.
 +
 
 +
пример:
 +
eeprom unsigned int x;
 +
 
 +
Если это первая переменная в EEPROM то её младший байт будет помещен в ячейку 1 EEPROM а старший в ячейку 2. Ячейка 0 не используется так как рекомендует производитель. CVAVR похоже не использует и 0 и 1 ячейки EEPROM.  Необходимо помнить что запись в  EEPROM длительный процесс - по таблице "Table 1. EEPROM Programming Time" это 8500 тактов процессора.
 +
 
 +
Количество записей в ячейки EEPROM ограничено ! 
 +
 
 +
Подробней в  "Accessing the AVR internal EEPROM".
 +
 
 +
Книги и учебники по радиоэлектронике и микроконтроллерам  там
 +
 
 +
Скачать весь курс по AVR одним архивом
 +
 
 +
 +
 
 +
Глобальные переменные объявляются до появления их в тексте какой либо функции. После объявления, глобальные переменные доступны в любой функции программы.
 +
 
 +
Локальные переменные объявляются в самом
 +
начале функций  - т.е. сразу после фигурной скобки    { 
 +
 
 +
Локальные переменные доступны только в той функции где они объявлены!  В разных функциях могут быть объявлены локальные переменные с одинаковыми именами - я не советую вам так делать. 
 +
 
 +
Советую не использовать ЛОКАЛЬНЫЕ переменные
 +
в главной функции main.
 +
 
 +
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p152  1.5.2 Подсчет символов ]
+
<source lang="C">
 +
<type definition> - тип данных которые может хранить переменная.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p153  1.5.3 Подсчет строк ]
+
наиболе часто используемые типы данных :
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p154  1.5.4 Подсчет слов ]
+
unsigned char - хранит числа от 0 до 255 (байт)
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p16  1.6 Массивы ]
+
unsigned int - хранит числа от 0 до 65535 (слово == 2 байта)
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p17  1.7 Функции ]
+
unsigned long int - хранит от 0 до 4294967295  (двойное слово == 4 байта)
 +
</source>
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p18  1.8 Аргументы. Вызов по значению ]
+
Подробнее все типы данных посмотрите в Help
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p19  1.9 Символьные массивы ]
+
CVAVR\bin\CVAVR.HLP
 +
 +
Раздел "Data Types"
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/1/#p110  1.10 Внешние переменные и область видимости]
+
Уточняйте ТИПЫ данных в руководстве к вашему компилятору !
 +
 +
Вместо unsigned char - можно писать писать просто  char, так как компилятор по-умолчанию считает char  без знаковым байтом.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/  Глава 2. Типы, операторы и выражения ]
+
А если вам нужен знаковый байт то объявляйте его так :
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p21  2.1 Имена переменных ]
+
signed char  imya_peremennoi;
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p22  2.2 Типы и размеры данных ]
+
<identifier> - имя переменной - некоторый набор символов по вашему желанию, но не образующий зарезервированные слова языка Си.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p23  2.3 Константы ]
+
Выше был уже пример идентификатора - имени переменной:
 +
imya_peremennoi
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p24  2.4 Объявления ]
+
 
 +
 +
Давайте осмысленные имена переменным и функциям - напоминающие, "говорящие" вам об их назначении.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p25  2.5 Арифметические операторы ]
+
Принято использовать маленькие буквы, а для отличия имен переменных от названия функций - имена переменных можно например начинать с буквы, а названия функций (кроме main конечно) с символа подчеркивания.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p26  2.6 Операторы отношения и логические операторы ]
+
Например так :
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p27   2.7 Преобразования типов ]
+
   moya_peremennaya        _vasha_funkziya
 +
 +
Внимание!
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p28  2.8 Операторы инкремента и декремента ]
+
Глобальные переменные, а также локальные с модификатором static - при старте и рестарте программы равны 0 если вы не присвоили им (например оператором =) иное значение при их объявлении или по ходу программы.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p29  2.9 Побитовые операторы ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p210   2.10 Операторы и выражения присваивания ]
+
Подробные примеры объявления переменных посмотрите
 +
пожалуйста в разделе Variables в "Хелп" компилятора CVAVR.   
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p211  2.11 Условные выражения ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/2/#p212  2.12 Приоритет и очередность вычислений]
+
Вот несколько примеров объявления переменных :
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/  Глава 3. Управление ]
+
unsigned char my_peremen = 34;
 +
unsigned int big_peremen = 34034;
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/#p31  3.1 Инструкции и блоки ]
+
Это объявлены две переменные и им присвоены значения.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/#p32  3.2 Конструкция if-else ]
+
Первая  my_peremen - символьного типа - это 1 байт, она может хранить
 +
число от 0 до 255. В данном случае в ней хранится число 34.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/#p33  3.3 Конструкцияn else-if ]
+
Вторая  big_peremen  - целого типа, два байта, в ней может хранится
 +
число от 0 до 65535 , а в примере в  неё поместили десятичное число 34034.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/#p34  3.4 Переключатель switch ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/#p35  3.5 Циклы while и ]
+
Пример массива содержащего  3 числа или элемента массива.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/#p36  3.6 Цикл do-while ]
+
char mas[3]={11,22,33};
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/#p37  3.7 Инструкции break и continue ]
+
Нумерация элементов начинается с  0.  
 +
Т.е. элементы данного массива называются
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/3/#p38  3.8 Инструкция goto и метки]
+
mas[0], mas[1], mas[2]
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/  Глава 4. Функции и структура программы ]
+
и в них  хранятся десятичные числа 11,  22 и 33.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p41  4.1 Основные сведения о функциях ]
+
Где то в программе вы можете написать:  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p42  4.2 Функции, возвращающие нецелые значения ]
+
mas[1] = 210;
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p43  4.3 Внешние переменные ]
+
Теперь  в  mas[1] будет хранится число  210
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p44  4.4 Области видимости ]
+
- массивы могут быть многомерными,
 +
- можно не присваивать значений элементам
 +
  массива при объявлении.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p45  4.5 Заголовочные файлы ]
+
НО только при объявлении вы можете присвоить значения всем элементам массива сразу ! Потом это можно будет сделать только индивидуально для каждого элемента.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p46  4.6 Статические переменные ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p47  4.7 Регистровые переменные ]
+
Строковая переменная  или массив содержащий строку символов.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p48  4.8 Блочная структура ]
+
char stroka[6]="Hello";
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p49  4.9 Инициализация ]
+
Символов (букв) между кавычками  5 , а я указал размер строки 6  !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p410  4.10 Рекурсия ]
+
Дело в том, что строки символов должны заканчиваться десятичным числом 0.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p411  4.11 Препроцессор языка Си ]
+
Не путайте его с символом '0' которому соответствует десятичное число 48 по
 +
таблице ASCII  - которая устанавливает каждому числу определенный символ.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p4111  4.11.1 Включение файла ]
+
Например :  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p4112  4.11.2 Макроподстановка ]
+
Элемент строки  stroka[1] содержит число 101  которому по таблице ASCII  соответствует символ 'e'
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/4/#p4113  4.11.3 Условная компиляция]
+
Элемент stroka[4] содержит число 111  которому соответствует символ 'o'
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/   Глава 5. Указатели и массивы ]
+
Элемент  stroka[5] содержит число 0  которому соответствует
 +
символ   'NUL'  его еще обозначают вот так  '\0'
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p51  5.1 Указатели и адреса ]
+
Строковая переменная может быть "распечатана" или выведена в USART MK вот так:
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p52  5.2 Указатели и аргументы функций ]
+
printf("%s\n", stroka);
 +
 +
Вы можете преобразовать строковую переменную в число! Если исходная строка символов такая  :  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p53  5.3 Указатели и массивы ]
+
char stroka[]="3654694";
 +
то вот так:
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p54  5.4 Адресная арифметика ]
+
perem_1 = atoi(stroka);
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p55   5.5 Символьные указатели функции ]
+
мы поместим в переменную  perem_1  (которую должны были ранее в программе объявить как  "беззнаковую целую") число 36546. 
 +
Это число влезет в переменную perem_1 которая может хранить числа от 0 до 65535.
 +
А вот 9 и 4 уже не поместятся. Для бОльших чисел есть функция  -   atol()
 +
Чтобы использовать эти функции необходимо включить в начале программы заголовочный файл :
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p56  5.6 Массивы указателей, указатели на указатели ]
+
#include <stdlib.h>
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p57  5.7 Многомерные массивы ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p58  5.8 Инициализация массивов указателей ]
+
Для преобразования числа в строку
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p59   5.9 Указатели против многомерных массивов ]
+
есть  itoa()  и  ltoa()    
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p510  5.10 Аргументы командной строки ]
+
и аналогичные функции для чисел с плавающей точкой.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p511  5.11 Указатели на функции ]
+
Подробнее об этих и других полезных функциях смотрите раздел
 +
"Standard Library Functions"  справки компилятора CodeVisionAVR.
 +
 +
Советую вам скачать  заголовочный файл
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/5/#p512  5.12 Сложные объявления]
+
m8 128.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/  Глава 6. Структуры ]
+
Он содержит названия битов МК ATmega8  -16 -32 -64 -128
 +
и сокращенные названия типов данных как в компиляторе IAR.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p61  6.1 Основные сведения о структурах ]
+
вот отрывок из  него:
 +
<source lang="C">
 +
#define u8 unsigned char // 0 to 255
 +
#define s8 signed char // -128 to 127
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p62  6.2 Структуры и функции ]
+
#define u16 unsigned int // 0 to 65535
 +
#define s16 signed int // -32768 to 32767
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p63  6.3 Массивы структур ]
+
#define u32 unsigned long int
 +
// 0 to 4294967295
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p64  6.4 Указатели на структуры ]
+
#define s32 signed long int
 +
// -2147483648 to 2147483647
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p65  6.5 Структуры со ссылками на себя ]
+
#define f32 float // ±1.175e-38 to ±3.402e38
 +
#define d32 double // ±1.175e-38 to ±3.402e38
 +
</source>
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p66  6.6 Просмотр таблиц ]
+
После включения моего  "хидера"  в текст вашей
 +
программы вы сможете писать вместо длинного
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p67  6.7 Средство typedef ]
+
unsigned long int <имя 32 битной переменной>
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p68  6.8 Объединения ]
+
коротко :
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/6/#p69  6.9 Битовые поля]
+
u32 <имя 32 битной переменной>
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/  Глава 7. Ввод и вывод ]
+
u - без знаковая - значит не отрицательная
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p71  7.1 Стандартный ввод-вывод ]
+
s - значит переменная со знаком
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p72  7.2 Форматный вывод (printf) ]
+
32 - количество бит в переменной
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p73  7.3 Списки аргументов переменной длины ]
+
 +
 +
==КОНСТАНТЫ.==
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p74  7.4 Форматный ввод (scanf) ]
+
flash  и  const  ставятся перед объявлением констант - неизменяемых данных хранящихся во флэш памяти программ. Они позволяют вам использовать не занятую программой память МК. Обычно для хранения строковых данных - различные информационные сообщения, либо чисел и массивов чисел.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p75  7.5 Доступ к файлам ]
+
КОНСТАНТЫ  ПРИМЕРЫ из CVAVR help
 +
<source lang="C">
 +
flash int integer_constant=1234+5;
 +
flash char char_constant=’a’;
 +
flash long long_int_constant1=99L;
 +
flash long long_int_constant2=0x10000000;
 +
flash int integer_array1[ ]={1,2,3};
 +
flash int integer_array2[10]={1,2};
 +
flash int multidim_array[2][3]={{1,2,3},{4,5,6}};
 +
flash char string_constant1[ ]=”This is a string constant”;
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p76  7.6 Управление ошибками (stderr и exit) ]
+
const char string_constant2[ ]=”This is also a string constant”;
 +
</source>
 +
'''В других компиляторах могут быть отличия !'''
 +
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p77  7.7 Ввод-вывод строк ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p78  7.8 Другие библиотечные функции ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p781  7.8.1 Операции со строками ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p782  7.8.2 Анализ класса символов и преобразование символов ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p783  7.8.3 Функция ungetc ]
+
Следующий пункт в структуре программы на Си для МК
 +
<source lang="C">
 +
пункт  5 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p784  7.8.4 Исполнение команд операционной системы ]
+
Описание функций-обработчиков прерываний.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p785  7.8.5 Управление памятью ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p786  7.8.6 Математические функции ]
+
Механизм прерываний подробно описан
 +
на странице 3  -  Прерывания в AVR
 +
 
 +
/*
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/7/#p787  7.8.7 Генератор случайных чисел]
+
Конкретно в  ЭТОЙ программе - есть только одно прерывание
 +
и значит одна функция обработчик прерывания.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/8/  Глава 8. Интерфейс с системой UNIX ]
+
Программа будет переходить на неё при возникновении прерывания :  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/8/#p81  8.1 Дескрипторы файлов ]
+
ADC_INT - по событию "окончание АЦ преобразования" 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/8/#p82  8.2 Нижний уровень ввода-вывода (read и write) ]
+
*/  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/8/#p83  8.3 Системные вызовы open, creat, close, unlink ]
+
interrupt [ADC_INT] void adc_isr(void)
 +
{
 +
PORTB=(unsigned char) (~(ADCW>>2));
 +
/* отобразить горящими светодиодами подключенными
 +
от + питания МК через резисторы 560 Ом к ножкам порта_B  старшие 8 бит результата аналого-цифрового преобразования 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/8/#p84  8.4 Произвольный доступ (lseek) ]
+
Сделаем паузу 127 мСек - просто как пример пауз */  
 +
delay_ms(127);
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/8/#p85  8.5 Пример. Реализация функций fopen и getc ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/8/#p86  8.6 Пример. Печать каталогов ]
+
/*
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/8/#p87  8.7 Пример. Распределитель памяти]
+
В реальных программах старайтесь
 +
не делать пауз в прерываниях !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/preface/a/  Приложение A. Справочное руководство ]
+
Обработчик прерывания должен быть
 +
как можно короче и быстрее.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a1   A1. Введение ]
+
Например - в обработчике прерывания вы только устанавливаете флаги (биты или переменная) означающие состояние кнопок, значения переменных или регистров, а обрабатываете  это уже в основном цикле программы, через конструкции  if - else  или  switch   (описаны выше!)
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2  A2. Соглашения о лексике ]
+
*/
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_1  A2.1. Лексемы (tokens) ]
+
// начать новое АЦПреобразование
 +
ADCSRA|=0x40;
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_2  A2.2. Комментарий ]
+
} // закрывающая скобка обработчика прерывания
 +
</source>
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_3  A2.3. Идентификаторы ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_4  A2.4. Ключевые слова ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_5  A2.5. Константы ]
+
Функция обработчик прерывания может быть названа
 +
вами  произвольно - как и любая функция кроме  main.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_5_1  A2.5.1. Целые константы ]
+
Здесь она названа :       adc_isr 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_5_2  A2.5.2. Символьные константы ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_5_3  А2.5.3. Константы с плавающей точкой ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_5_4  A2.5.4. Константы-перечисления ]
+
При каком прерывании ее вызывать - компилятор узнает из строчки :  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a2_6   A2.6. Строковые литералы ]
+
interrupt[ADC_INT]    
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a3  A3. Нотация синтаксиса ]
+
по первому зарезервированному слову - interrupt - он узнаёт,
 +
что речь идет об обработчике прерывания,
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a4  A4. Что обозначают идентификаторы ]
+
а номер вектора прерывания (адрес куда физически, внутри МК перескочит программа при возникновении прерывания) будет подставлен вместо ADC_INT препроцессором компилятора перед компиляцией - этот номер указан в подключенном нами ранее заголовочном файле ("хидере") описания "железа" МК - mega16.h - это число сопоставленное слову ADC_INT. Не ленитесь, посмотрите в файле !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a4_1  A4.1. Класс памяти ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a4_2  A4.2. Базовые типы ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a4_3  A4.3. Производные типы ]
+
Очень информативна и тем ценна для
 +
обучающегося следующая строка программы:
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a4_4  A4.4. Квалификаторы типов ]
+
PORTB = (unsigned char) (~(ADCW >> 2));
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a5  A5. Объекты и Lvalues ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6  A6. Преобразования ]
+
Давайте проанализируем как она работает.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6_1  A6.1. Целочисленное повышение ]
+
=    оператор присваивания. Он означает присвоить значение вычисления выражения
 +
справа от оператора присваивания той переменной что указана слева от него.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6_2  A6.2. Целочисленные преобразования ]
+
Значит нужно вычислить выражение справа и поместить его в переменную  PORTB.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6_3  A6.3. Целые и числа с плавающей точкой ]
+
Вычислим что справа от оператора присваивания.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6_4  A6.4. Типы с плавающей точкой ]
+
ADCW - это переменная слово (двухбайтовая величина - так она объявлена в файле mega16.h) в котором CodeVisionAVR сохраняет 10-битный результат АЦП - а именно в битах9_0 (биты с 9-го по 0-й) т.е. результат выровнен обычно - вправо.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6_5  А6.5. Арифметические преобразования ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6_6  A6.6. Указатели и целые ]
+
VMLAB имеет только 8 светодиодов  - значит нужно отобразить 8 старших бит результата - т.е. биты_9_2  - для этого мы сдвигаем все биты слова ADCW  вправо на 2 позиции
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6_7  A6.7. Тип void ]
+
ADCW >> 2 /* биты 1 и 0 вылетают вправо из числа в небытие,
 +
бит_9 перемещается в позицию бит_7, бит_8 в позицию бит_6 и
 +
так далее до бит_2 становится бит_0  */
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a6_8  А6.8. Указатели на void ]
+
Теперь старшие 8 бит результата АЦП встали в биты7_0
 +
младшего байта  (LowByte - LB) слова ADCW
 +
>> n означает сдвинуть все биты числа вправо на n  позиций
 +
это равносильно делению на 2 в сепени n
 +
   
 +
<< n
 +
означает сдвинуть все биты числа влево на n позиций
 +
это равносильно умножению на 2 в сепени n
 +
 +
 +
Сдвиг используется очень часто !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7  A7. Выражения ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_1  A7.1. Генерация указателя ]
+
Светодиоды подключены так как написано выше - т.е. подключены правильно !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_2  A7.2. Первичные выражения ]
+
Загораются (показывая "1") при "0" на соответствующем выводе МК - значит нам нужно выводить в PORTB число в котором "1" заменены "0" и наоборот  - 
 +
это делает как я рассказал выше:  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_3  A7.3. Постфиксные выражения ]
+
~    операция побитного инвертирования - меняет значения битов.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_3_1  A7.3.1. Обращение к элементам массива ]
+
Значит результатом этого выражения
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_3_2  A7.3.2. Вызов функции ]
+
~(ADCW >> 2)
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_3_3  A7.3.3. Обращение к структурам ]
+
будут инвертированные 8 старших бит результата АЦП находящиеся
 +
в младшем (правом - LB) байте двух байтового слова ADCW
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_3_4  A7.3.4. Постфиксные операторы инкремента и декремента ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4  А7.4. Унарные операторы ]
+
Выше я уже говорил что :  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4_1  А7.4.1. Префиксные операторы инкремента и ]
+
в Си в переменную можно помещать только тот тип данных который она может хранить !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4_2  A7.4.2. Оператор получения адреса ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4_3  A7.4.3. Оператор косвенного доступа ]
+
Так как PORTB это байт, а ADCW - это два байта, то прежде чем выполнить оператор присваивания (это знак  = ) нужно преобразовать слово (слово - word - значит два байта)  ADCW  в без знаковый байт.
 +
Преобразование типов данных - делают так :  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4_4  A7.4.4. Оператор унарный плюс ]
+
перед тем что надо преобразовать записывают в скобках (      )
 +
тип данных к которому нужно преобразовать.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4_5  A7.4.5. Оператор унарный минус ]
+
====Пишем ...====
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4_6  A7.4.6. Оператор побитового отрицания ]
+
(unsigned char) (~(ADCW>>2))
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4_7  A7.4.7. Оператор логического отрицания ]
+
Результат этой строки - один байт и мы можем поместить его в PORTB
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_4_8  A7.4.8. Оператор определения размера sizeof ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_5  A7.5. Оператор приведения типа ]
+
Если в регистре DDRB все биты равны "1" - т.е. все ножки порта_B выходы, мы безусловно увидим старшие 8 бит результата АЦП горящими светодиодами.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_6  A7.6. Мультипликативные операторы ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_7  A7.7. Аддитивные операторы ]
+
Вам должна быть абсолютно понятна разобранная строка:
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_8  A7.8. Операторы сдвига ]
+
PORTB = (unsigned char) (~(ADCW>>2));
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_9  A7.9. Операторы отношения ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_10   A7.10. Операторы равенства ]
+
Если это не так   то
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_11  A7.11. Оператор побитового И ]
+
повторите разбор, и перечитайте материал по Си по использованным операторам Си.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_12  A7.12. Оператор побитового исключающего ИЛИ ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_13  A7.13. Оператор побитового ИЛИ ]
+
Разберем еще одну строчку
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_14  A7.14. Оператор логического И ]
+
ADCSRA|=0x40;
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_15  A7.15. Оператор логического ИЛИ ]
+
Обратите внимание на необходимость ставить в конце
 +
выражений точку с запятой - не забывайте !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_16  А7.16. Условный оператор ]
+
'''Эта строка означает следующее:''' 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_17  A7.17. Выражения присваивания ]
+
Двигаемся слева на право :
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_18  A7.18. Оператор запятая ]
+
- берем значение переменной ADCSRA (это регистр МК - значит программа прочитает его, возьмет число из него) 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a7_19   A7.19. Константные выражения ]
+
- выполняем с этим числом операцию обозначаемую вертикальной черточкой  
 +
( это поразрядная операция ИЛИ - только "0" и "0" дают "0" ) с числом 0x40
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8  A8. Объявления ]
+
- присвоим или поместим результат поразрядного ИЛИ обратно в переменную ADCSRA - т.е. запишем результат в регистр ADCSRA 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_1  A8.1. Спецификаторы класса памяти ]
+
0x40  это в двоичном виде: 0100 0000
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_2  А8.2. Спецификаторы типа ]
+
так как в результате поразрядного  ИЛИ только два "0" дают "0" биты в ADCSRA напротив нулей не изменятся, а вот бит_6 в  ADCSRA оказывается напротив "1" и теперь он станет "1" не зависимо от того каким он был до этого !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_3  A8.3. Объявления структур и объединений ]
+
т.е. смысл рассматриваемой строки программы
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_4  A8.4. Перечисления ]
+
ADCSRA|=0x40;
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_5  А8.5. Объявители ]
+
"установить" (т.е. сделать "1") бит_6  в  регистре ADCSRA
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_6   A8.6. Что означают объявители ]
+
 
 +
Число справа от составных операторов    |=   &=  ^= обычно называют маской,
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_6_1  A8.6.1. Объявители указателей ]
+
и говорят "наложить маску" - так как в результате меняются лишь те биты которые нужно изменить.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_6_2  А8.6.2. Объявители массивов ]
+
Управление отдельными битами в переменной или регистре.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_6_3  А8.6.3. Объявители функций ]
+
Как изменить только некоторые биты не изменяя остальные.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_7   A8.7. Инициализация ]
+
Для обнуления нужных бит используют обозначаемое знаком & поразрядное логическое И   -  только
 +
"1" и "1" дает "1"
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_8  A8.8. Имена типов ]
+
PEREM &=(~0x04); // обнулить бит_2 в переменной PEREM Скобки здесь я добавил для улучшения читаемости кода.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_9  А8.9. Объявление ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a8_10  A8.10. Эквивалентность типов ]
+
Самоконтроль - важно:
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a9  A9. Инструкции ]
+
а) обязательно разберитесь почему обнуляется бит_2
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a9_1  A9.1. Помеченные инструкции ]
+
б) Как в двоичном виде выглядит результат  (~0x04)
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a9_2  A9.2. Инструкция-выражение ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a9_3  A9.3. Составная инструкция ]
+
А вот так более понятно:  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a9_4  A9.4. Инструкции выбора ]
+
  PEREM &=(~(1 << 2)); // обнулить бит_2 в переменной PEREM
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a9_5  A9.5. Циклические инструкции ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a9_6  A9.6. Инструкции перехода ]
+
Обнулить биты  5, 3 и 0  в переменной  PEREM
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a10   А10. Внешние объявления ]
+
   PEREM &=(~ (  (1 << 5)|(1 << 3)|(1 << 0)  ) );
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a10_1  A10.1. Определение функции ]
+
конечно здесь вместо (1 << 0) можно написать просто (1)
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a10_2  A10.2. Внешние объявления ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a11  A11. Область видимости и связи ]
+
"Установить" - сделать "1" -  биты  7, 5 и 3  в переменной  PEREM
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a11_1   A11.1. Лексическая область видимости ]
+
   PEREM |=(1 << 7)|(1 << 5)|(1 << 3);
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a11_2  A11.2. Связи ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12  A12. Препроцессирование ]
+
Обязательно разберитесь как это работает - вы должны это понимать и ГЛАВНОЕ использовать в своих программах.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_1  A12.1. Трехзнаковые последовательности ]
+
Например (1 << 4) означает: взять число 1 и все его биты сдвинуть в лево на 4 позиции - в итоге мы получим двоичное  10000. Эти вычисления компилятор сделает сам и в программе заменит всё, что правее  =  на число-результат.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_2  A12.2. Склеивание строк ]
+
Вместо номеров битов вы можете использовать их названия из даташит.  
 +
Но в  CVAVR для этого надо включить мой заголовок о котором написано выше или самому сделать определения битов из архива выложеного выше. А в IAR надо отметить галочку "Элау бит дефинишнс" в свойствах проекта.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_3   А12.3. Макроопределение и макрорасширение ]
+
   WDTCR |= (1 << WDTOE) | (1 << WDE);
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_4  A12.4. Включение файла ]
+
эта строка программы "Установит" - сделает "1" биты  WDTOE и WDE  в регистре WDTCR
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_5   A12.5. Условная компиляция ]
+
    
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_6  A12.6. Нумерация строк ]
+
<source lang="C"> 
 +
/* Пункт 6      Функции используемые в программе  */
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_7  A12.7. Генерация сообщения об ошибке ]
+
// их может быть столько сколько вам нужно.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_8  A12.8. Прагма ]
+
// у нас будет одна, кроме main и
 +
// обработчика прерывания.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_9  A12.9. Пустая директива ]
+
/*  =================================
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a12_10  A12.10. Заранее определенные имена ]
+
Это будет функция в которой описано начальное
 +
конфигурирование МК в соответствии с
 +
поставленной задачей
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/a/#a13  A13. Грамматика]
+
Удобно над функцией сделать заголовок
 +
подробно поясняющий назначение функции !
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/  Приложение B. Стандартная библиотека ]
+
=====================================  */
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b1  B1. Ввод-вывод: stdio. ]
+
(void)_init_mk(void) {
 +
/* Вначале любой функции объявляются
 +
ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ - если конечно они вам нужны */
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b11  B1.1. Операции над файлами ]
+
/* void - означает пусто.  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b12  B1.2. Форматный вывод ]
+
Перед названием функции - void - означает что функция не возвращает ни какого значения. А в скобках после названия означает что при вызове в функцию не передаются ни какие значения. */
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b13  B1.3. Форматный ввод ]
+
// инициализация Port_B
 +
DDRB=0xFF;  // все ножки сделать выходами
 +
PORTB=0xFF; // вывести на все ножки "1"
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b14  B1.4. Функции ввода-вывода символов ]
+
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b15  B1.5. Функции прямого ввода-вывода ]
+
/* настройка АЦП - производится записью определенного числа в регистр "ADC Control and Status Register A" – ADCSRA
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b16  B1.6. Функции позиционирования файла ]
+
посмотрите его описание в ДШ МК мега16.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b17  B1.7. Функции обработки ошибок ]
+
Нам нужно:  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b2  B2. Проверки класса символа: ctype. ]
+
- Включить модуль АЦП
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b3  B3. Функции, оперирующие со строками: string. ]
+
- Установить допустимую частоту тактирования АЦП при частоте кварца 3.69 МГц  - мы выберем коэф. деления 64 - это даст частоту такта для процессов в АЦП  57.656 КГц
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b4  B4. Математические функции: math. ]
+
- Включить прерывание по завершению АЦ преобразования.
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b5  B5. Функции общего назначения: stdlib. ]
+
По ДШ для этого нужно записать в регистр ADCSRA
 +
число: 1000 1110  или 0х8E  */
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b6  B6. Диагностика: assert. ]
+
// ADC initialization w Oscillator=3.69MHz
 +
// ADC Clock frequency: 57.656 kHz
 +
// ADC Interrupts: On
 +
ADCSRA=0x8E;
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b7  B7. Списки аргументов переменной длины: stdarg.]
 
 
   
 
   
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b8  B8. Дальние переходы: setjmp. ]
 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b9  B9. Сигналы: signal. ]
+
/* Теперь выбираем вход АЦП ADC0 (ножка PA0) и внешнее опорное напряжение (это напряжение код АЦП которого будет 1023) с ножки AREF 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b10  B10. Функции даты и времени: time. ]
+
Смотрим что нужно записать для этого в регистр
 +
мультиплексора (выбора входа) АЦП ADMUX 
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/b/#b111  B11. Зависящие от реализации пределы: limits.и float.]
+
см. ДШ */  
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/cПриложение С. Перечень измененийhr ]
+
// Нужно записать 0 (он там по-умолчанию)
 +
ADMUX=0;
 +
 
 +
 
 +
 
 +
/* Разрешаем ГЛОБАЛЬНО все прерывания
 +
      разрешенные индивидуально !
 +
 
 +
Вы наверно поняли что индивидуально мы разрешили
 +
лишь прерывание по завершении АЦП - вот оно то и
 +
сможет возникать у нас.  */
 +
#asm("sei")
 +
</source>
 +
 
 +
'''Внимание !'''
 +
 
 +
Так делаются Ассемблерные вставки в CVAVR :
 +
 
 +
#asm ("инструкция на ассемблере")
 +
 
 +
Обратите внимание - точки с запятой в конце НЕТ !  Такие вставки принято иногда делать.  НО они не являются необходимыми.
 +
 
 +
На языке Си можно управлять ВСЕМИ программно
 +
изменяемыми битами в регистрах МК !
 +
 
 +
 
 +
Напоминаю ...   
 +
 
 +
Все регистры МК перечислены в таблице в конце ДШ с указанием номеров страниц с подробным описанием регистра и его битов.
 +
 
 +
Часто используются такие ассемблерные вставки :
 +
<source lang="C">
 +
#asm("sei") // Разрешить ГЛОБАЛЬНО все прерывания
 +
 
 +
#asm("cli") // Запретить ГЛОБАЛЬНО все прерывания
 +
 
 +
#asm("nop") // Пауза в 1 такт процессора
 +
 
 +
#asm("wdr") // Сбросить сторожевой таймер
 +
 
 +
 
 +
// все функция закончена
 +
} // скобка закрывающая для функции _init_mk()
 +
 +
Далее...
 +
/*
 +
  Пункт 7      Главная функция  main()  -  обязательная !
 +
*/
 +
 
 +
/*  =================================
 +
Главная функция -
 +
 
 +
Си программа начинает выполнятся с нее!
 +
 
 +
=====================================  */
 +
 
 +
void main(void){
 +
/* Вначале любой функции объявляются
 +
  (если нужны)  ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ  */
 +
 
 +
_init_mk();/*Вызываем функцию инициализации, настроийки аппаратуры МК. Выполнив ее программа вернется сюда и будет выполнять следующую строку  */
 +
 
 +
// запускаем первое АЦП
 +
ADCSRA|=0x40;
 +
 
 +
// бесконечный цикл в ожидании прерываний
 +
while(1);
 +
/* Программа будет крутится на этой строчке постоянно проверяя истинно ли условие в
 +
скобках после while а так как там константа
 +
1 - то условие будет истинно всегда!
 +
 
 +
  // функция main закончена
 +
} // скобка закрывающая для функции main()
 +
</source>
 +
 
 +
 
 +
 +
 
 +
'''Эта программа на Си будет работать так :'''
 +
 
 +
По завершении АЦП будет возникать прерывание и программа будет перескакивать в функцию обработчик прерывания  adc_isr()
 +
 
 +
При этом будут автоматически запрещены все прерывания ГЛОБАЛЬНО !
 +
 
 +
В конце  adc_isr() запускается новое АЦ преобразование и при выходе из обработчика прерывания снова разрешаются глобально прерывания, и программа возвращается опять в бесконечный цикл  while(1)
 +
 
 +
Такая чехарда будет продолжаться пока есть питание МК и не будет сброса.   
 +
 
 +
Светодиоды будут высвечивать 8-ми битный код АЦП напряжения на ножке PA0 
 +
 
 +
'''Всё - программа на Си написана и разобрана.'''
 +
 
 +
Вам должно быть все ясно и  абсолютно понятно!
 +
 
 +
Если это не так то перечитайте, подумайте,
 +
повторите разбор, почитайте рекомендованное ниже по Си.
 +
 
 +
==Еще щепотка  Си :==
 +
 
 +
=====Пример:===== 
 +
делать что-то  пока на ножке PBn есть "1"
 +
 
 +
Как AVR переводит напряжения на выводах МК в логические уровни - рассказано с картинками, графиками на [[AVR123:Страница|2странице 2]] курса - Устройство микроконтроллера AVR.
 +
<source lang="C">
 +
while(PINB & (1 << n)){ // для любого компилятора
 +
            Какой-то код программы   
 +
/* Какой-то код будет выполнятся снова и снова, пока проверка условия в скобках после while будет давать "истину" - значит пока на ножке PBn есть логическая единица 
 +
 
 +
Проверка условия выполняется в начале и затем каждый раз по завершении выполнения какого-то кода
 +
 
 +
Пока выполняется какой-то код проверка того что на ножке PBn не производится. */
 +
                                              };
 +
 
 +
примечание  -  в CVAVR можно написать проще 
 +
while(PINB.n){  // но для регистров с адресом до 31
 +
 
 +
 +
 
 +
Пример:  выполнить что-то если  на ножке PCn есть "0"
 +
 
 +
if((~PINC)&(1 << n)){ // для любого компилятора
 +
                    что-то
 +
/* что-то начнет выполняться если на ножке PCn "0" */
 +
                    };
 +
 
 +
примечание  -  в CVAVR можно написать проще 
 +
if(!(PINC.n)){
 +
 
 +
 
 +
Помните !      Выполнение  чего-то  может быть прервано прерыванием.
 +
После завершения обработки прерывания выполнение чего-то продолжится.
 +
 
 +
Примечание  -  Условие : 
 +
 
 +
if((~PINC)&(1 << n)) {
 +
 
 +
можно записать и вот так :
 +
 
 +
if(!(PINC & (1 << n))) {
 +
 
 +
 +
 
 +
Пример:  выполнить что-то если  на ножке PBn есть "1"
 +
 
 +
if((PINB)&(1 << n)){ // для любого компилятора
 +
                    что-то
 +
/* что-то начнет выполняться если на ножке PBn "1" */
 +
                    };
 +
 
 +
примечание  -  в CVAVR можно написать проще 
 +
if(PINB.n){
 +
</source>
 +
К  битам  регистров с адресами от 0 до 31 в компиляторе CodeVisionAVR можно обратится (и читать и записывать) проще.
 +
 
 +
Вот так:    REGISTR.BIT 
 +
 +
Пример:
 +
<source lang="C"> 
 +
PINB.2  или  PORTA.5    или  DDRC.7
 +
</source>
 +
Пример:
 +
<source lang="C">
 +
if(!PINB.2){
 +
                этот код /* Если на ножке PB2 низкий
 +
логический уровень - то выполнить этот код */
 +
          };    
 +
 
 +
Пример:
 +
PORTA.3 = 1; /* Сделать бит 3 в регистре
 +
PORTA единицей - говорят: "установить бит"
 +
по англ. "set bit" */
 +
 
 +
Пример:
 +
PORTB.6 = 0; /*  Сделать бит 6 в регистре
 +
PORTB нулем - говорят: "очистить, сбросить бит"
 +
по англ. "clear bit"  */
 +
</source>
 +
 +
Битовые операции подробно описаны  в  [[AVR123:задача_1|задаче 1]]
 +
 
 +
и конечно в справке -  help - компиляторов !
 +
 
 +
=====Теперь вы должны знать=====
 +
 
 +
- как записать число в регистр, в переменную
 +
 
 +
- как изменить бит в регистре 
 +
 
 +
- как взять число из регистра
 +
 
 +
- как выполнить что-то в зависимости от
 +
  значения бита в регистре или в переменной
 +
 
 +
- записывайте возникающие вопросы !
 +
    и лучше на бумагу - моторная память !
 +
 
 +
- найдите в DataSheet (ДШ) регистры и устройства МК использованные в задаче, прочитайте о  них подробней.
 +
 
 +
- если вопросы остались перечитайте задачу снова !
 +
 
 +
- если вопросы не разрешены, ищите ответ:
 +
 
 +
1) в help и документации компилятора, симулятора, других используемых программ!
 +
 
 +
2) поиском Windows в папках и help компилятора и симулятора.
 +
 
 +
3) поиском Windows в папке где сохранен у вас курс.
 +
 
 +
4) в моем не структурированном мини-AVRFAQ - это сборник ответов на часто задаваемые мне по курсу вопросы и советы по применению МК от знающих людей.
 +
 
 +
 +
Дальше - страница 6
 +
 
 +
Задачи - Упражнения Курса
 +
Практическая работа с Компилятором с Симулятором с МК и внешними устройствами 
 +
  
[http://masterpc.alfaspace.net/books/CCScience/book_C_programming/pointer/  Предметный указатель - язык Си ]
 
  
 
--[[Участник:Nekolex|Nekolex]] 20:47, 27 сентября 2009 (UTC)
 
--[[Участник:Nekolex|Nekolex]] 20:47, 27 сентября 2009 (UTC)

Текущая версия на 00:47, 29 сентября 2009

Вернуться на главную

Язык Си для AVR.

Как раз то, что необходимо и достаточно для микроконтроллеров.

По умолчанию компилятор CVAVR

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

Минимальная программа на Си может быть такой: <source lang="c">main(){}</source> Эта программа не делает ни чего полезного — но это уже программа и она показывает что в программе на языке Си — должна быть главная функция main — обязательно !

Скачайте и Распечатайте.Памятка Си для МК на ОДНОЙ странице.

Рассказывая про МК я говорил вам, что: Задача программы МК:

  • читать числа из регистров и памяти МК,
  • делать что-то с числами, данными и
  • записывать числа в регистры и память.

Только так программа может общаться с МК.

Как это делать на языке Си

Регистры МК
( регистры - это ячейки-байты в памяти МК AVR ) в программе на Си имеют названия как и в ДШ и так как числа в большинстве из них можно менять - для программы регистры являются по сути переменными.
Переменная
- это набор ячеек в памяти в которых можно хранить число или числа и менять их. Переменная имеет адрес и имя.
Константа
- это как переменная но менять содержимое нельзя.

Подробней о переменных и константах написано ниже.

1) Чтобы поместить число в переменную (в регистр) в языке Си есть оператор присваивания

это знак "=" ( называемый в математике "равно" ) "=" в Си означает вычислить результат того что справа от оператора присваивания и поместить этот результат в переменную находящуюся левее оператора присваивания.

Информация
Запомните!

В Си знак "=" НЕ означает равенство!



<source lang="c"> PORTB = PINB + 34;/* Эта строчка на Си означает взять (прочитать, считать) значение переменной (регистра) PINB, затем прибавить к нему число 34 и поместить результат в переменную PORTB */

ПЕРЕМЕННАЯ = PINC; /* Эта строчка на Си означает взять (прочитать, считать) значение переменной (регистра) PINC и поместить результат в переменную с именем ПЕРЕМЕННАЯ */ </source> Чтобы в Си взять (прочитать) число из регистра или значение переменной нужно написать его название НЕ непосредственно с лева от оператора присваивания !

Примеры :
a) Строка где переменная стоит слева от = но через знак &

<source lang="c">PORTB & = 0x23;</source>

на Си означает - прочитать содержимое переменной PORTB, затем выполнить "поразрядное (побитное) логическое И" между прочитанным значением и числом 0x23 и поместить (записать, присвоить) результат в переменную PORTB

b) Строка где переменная стоит непосредственно слева от =

<source lang="c">PORTB = 0x23;</source>

на Си означает - не читая содержимое переменной PORTB присвоить ей значение 0x23 уничтожив то что было там раньше.

:Вместо & "И" (AND - только 1 и 1 дают 1) могут быть и другие побитные логические операции:
• | "ИЛИ" (OR только 0 и 0 дают 0)
• ^ "Исключающее ИЛИ" (XOR изменить бит напротив "1")
• ~ "инвертирование битов" (INV изменить биты регистра)
• арифметические операции: + - * / %

С оператором присваивания используются вот такие сокращения:

ДЛИННАЯ ЗАПИСЬ СМЫСЛ СОКРАЩАЕТСЯ ДО
x = x + 1; добавить 1 x++; или ++x;
x = x - 1; вычесть 1 x--; или --x;
x = x + y; прибавить y x += y;
x = x - y; вычесть y x -= y;
x = x * y; умножить на y x *= y;
x = x / y; поделить на y x /= y;
x = x % y; остаток от деления x %= y;
x--; вычесть 1 x -= 1;
x++; добавить 1 x += 1;
Примеры :

<source lang="c"> 00010010 | 01001111 // "ИЛИ" - только 0 и 0 дают 0 // англ. название OR

01011111 // это результат

// только биты_5 в обоих числах были нули

00010010 & 01001111 // "И" - только 1 и 1 дают 1 // англ. название AND

00000010 // это результат

// только биты_2 в обоих числах были единицы

00010010 ^ 01001111/* "исключающее ИЛИ" - результат любое из пары чисел в котором инвертированы (изменены) биты напротив битов равных "1" в другом числе. англ. название XOR */ 01011101 // это результат /* изменились биты во втором числе напротив установленных битов 4 и 1 первого числа. */

~ 01001111 /* инвертировать биты те что были "1" станут "0" и наоборот */ 10110000 // это результат</source>

Запомните !
Результатом поразрядных (побитных)

логических операций : & | ^ ~ является число ! Которое может быть интерпретировано компилятором как "истина" если оно не ноль и "ложно" если число ноль.

Числа

В компиляторе можно записывать в виде указанном в его Help ! Раздел - константы - Constants.

например - Целые числа могут быть записаны : <source lang="c"> - в десятичной форме - 1234

- в двоичной форме с префиксом 0b так: 0b101001

- в шестнадцатеричной форме с префиксом 0x так: 0x5А

- в восьмеричной форме с префиксом 0 так: 0775</source>

Числа с плавающей точкой имеют в записи эту точку и какое либо число после этой точки, так: <source lang="c">61.234 или так: 73.0 и так: .786

и могут иметь в конце F вот так: 61.234F</source> ТОЧКА ОБЯЗАТЕЛЬНА !

Различные представления числа D3h равно 0xD3 равно 0b1101 0011 равно 211
шестнадцатеричное число 0xD3
0 x D 3
двоичное представление - число 0b1101 0011
0 b 1 1 0 1 0 0 1 1
номера бита 7 6 5 4 3 2 1 0
два в степени равной номеру бита
128 64 32 16 8 4 2 1
число 211 в десятичном виде это сумма степеней двойки где биты равны "1"
Сложите +128 +64 +16 +2 +1

Четыре бита это 1 "нибл" (полубайт) или 1 символ в 16-ричной системе или десятичное число от 0 до 15.

"В уме" удобно оперировать ниблами:двоичный десятичный 16-ричный

двоичный десятичный 16-ричный
0000 0
0001 1
0010 2
0011 3
0100 4
0101 5
0110 6
0111 7
1000 8
1001 9
1010 10 A
1011 11 B
1100 12 C
1101 13 D
1110 14 E
1111 15 F

Для перевода чисел из одного вида в другой можно использовать калькулятор Windows в инженерном виде.

Есть в Си операции которые изменяют значение переменной и без оператора присваивания : <source lang="c"> PORTA++; /* Эта строчка на Си означает взять значение переменной PORTA добавить к ней 1 и записать результат обратно в PORTA говорят: Инкрементировать регистр PORTA */

PORTC--; /* Эта строчка на Си означает обратное действие! Декрементировать - вычесть 1 из значения регистра PORTC */ </source>

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

Важно помнить что они имеют очень низкий приоритет - поэтому чтобы быть уверенными в порядке выполнения желательно писать их отдельной строчкой программы !

Информация
Обратите внимание !

В конце выражения или конструкции в программе на Си ставят точку с запятой.



Длинные выражения можно писать в несколько строк. <source lang="c"> /* ЗЕЛЕНЫМ я пишу комментарий к программе в Си он может быть написан в несколько строк

и пустых строк тоже */

// или в одну после двух черточек </source> Компилятор игнорирует все что написано в комментариях !

Вы не компилятор !

Не игнорируйте, пишите комментарии и читайте !

Когда инкремент или декремент используется в выражении то важно где стоят два знака + или - перед переменной или после переменной : <source lang="c"> a=4; b=7;

a = b++; /* Эта строчка на Си означает Взять значение переменной b присвоить его переменной a затем добавить 1 к переменной b и сохранить результат в b

Теперь a будет содержать число 7 b будет содержать число 8 */

a=4; b=7;

a = ++b; /* Эта строчка на Си означает Взять значение переменной b затем добавить к нему 1 и сохранить результат в b и этот же результат присвоить переменной a

Теперь a будет содержать число 8 и b будет содержать число 8 */ </source>

2) Арифметические операции в Си

<source lang="c"> x + y // сложение x - y // вычитание x * y // умножение

x / y /* деление.

Если числа целые результат - целое число с отброшенной дробной частью - не округленное !

т.е. если в результате деления на калькуляторе получается 6.23411 или 6.94 то результат будет просто целое число 6 - запомните !

Если числа с плавающей точкой, то есть float или double и записываются с точкой и числом после точки, то и результат будет число с плавающей точкой без отбрасывания дробной части 131.9739 / 6.18 даст 21.355 */

x % y // вычислить остаток от деления нацело

// примеры:

5 / 2 // даст 2

5 % 2 // даст 1

75 / 29 // даст 2

75 % 29 // даст 17 </source>

3) Операторы сравнения (или отношения):

<source lang="c"> используются для сравнения переменных, чисел (констант) и выражений. x < y // X меньше Y x > y // больше x <= y // меньше или равно x >= y // больше или равно x == y // равно x != y /* не равно

Результат выполнения этих операторов:

"истина" это "1" (точнее "не ноль")

"ложно" это "0"

Значения хранимые в переменных (в регистрах) х и у НЕ изменяются!

Берутся (считываются) значения хранящиеся (или содержащиеся) в переменных и сравниваются */

! /* "НЕ" - логическое отрицание */ </source>

4) Логические операции :

<source lang="c"> | | // "ИЛИ" - только "ложь" и "ложь" // дают "ложь"

&& // "И" - только "истина" и "истина" // дают "истина"

! // "НЕ" - логическое отрицание

/* Правило - в Си считается:

"Ложь" (False) только ноль.

"Истина"(True)- не ноль. или так: (!0)

  • /

!(истина) // дает "ложь"

!(ложь) // дает "истина" </source> В результате логической операции вы получаете НЕ ЧИСЛО, а логическое значение "истина" или "ложь"

Для логических операций && и || берутся результаты выражений слева и справа от знака операции преобразованные в "истину" или "ложь" и определяется логический результат операции.

Компилятор, для определенности наверно, результат "истина" превращает в 1 а не в любое отличное от 0 число.

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

Пример:

<source lang="c"> if((выражение1)&&((выражение2) || (выражение3))) {/* Код программы здесь будет выполняться если: Выражение1 "Истина" (значит не ноль) и хотя бы одно из выражений 2 и 3 тоже "Истина" (значит не ноль).

  • /};</source>

Подробнее о логических операциях обязательно прочитайте по в низу этой страницы !

Приоритет операций в языке Си перечислены в порядке убывания приоритета. Операции, приведённые на одной строчке, имеют одинаковый приоритет. Операции, помеченные как R->L, исполняются справа налево.

  1. () [] -> .
  2. Унарные (R->L): ! ~ - * & sizeof (type) ++ --
  3. Бинарные арифметические: * / %
  4. Бинарные арифметические + -
  5. Сдвиг: << >>
  6. Сравнение: < <= > >=
  7. Сравнение: == !=
  8. Битовая: &
  9. Битовая: ^
  10. Битовая: |
  11. Логическая: &&
  12. Логическая: ||
  1. Тернарная (R->L): ?:
  2. Операции с присваиванием (R->L):
= += -= = /= &= |= ^= <<= >>=

{

{InfoBlock|Чтобы точно знать порядок выполнения операций программой используйте скобки ( )

( () + ( () * () ) ) Ведь скобки ( ) имеют наивысший приоритет.|Совет:}}

Самое интересное !

Ходовые конструкции на Си В компиляторе [CVAVR заготовки этих конструкций находятся под ярлыком "Code Templates" слева вверху. Вы можете выбирать нужные заготовки и вставлять их в свою программу.

05 temp.png

5) if(){ }else{ }; идеальная конструкция если вам нужно выполнить какую то часть программы при наличии каких либо

условий или при их отсутствии :

<source lang="c"> if (выражение) { код на Си /* делать этот код если выражение "истина" - т.е. результат его вычисления не ноль */ } else { код на Си /* делать этот код если выражение "ложь" - т.е. результат его вычисления равен нулю */ };

// } else { это не обязательный элемент конструкции, без него так :

if (выражение) { код на Си /* делать этот код если выражение "истина" - т.е. результат его вычисления не ноль */ }; </source>

6)while(){ }; условный цикл ( цикл с условием ) - используйте если вам

нужно выполнять какой то код программы пока выполняется (существует,

справедливо, "истино" - значит "не ноль") некоторое условие, результат вычисления выражения :

<source lang="c"> while (выражение) { код на Си /* делать этот код если выражение "истина" - т.е. результат его вычисления не ноль. Пока выполняется этот код выражение не проверяется на истинность ! После выполнения кода происходит переход к строке while снова проверять истинность выражения */ }; </source> Цикл while имеет вариант

do - while при котором код в { } выполняется по меньшей мере один раз не зависимо от истинности условия в скобках : <source lang="c"> do { код на Си /* сделать этот код один раз

затем, если выражение есть "истина" - т.е. результат его вычисления не ноль - опять делать код с начала, и так до тех пор пока выражение истина */ } while (выражение); </source> 7) for(;;){ }; - этот цикл позволяет выполнить часть программы нужное число раз: <source lang="c"> char i; /* объявление переменной для for это обычная переменная Си и значит может иметь любое допустимое имя по вашему желанию и тип */ for (i=5; i i = 5 это начальное выражение, то что в начале будет в переменной i

Число 5 просто для примера, может быть таким, как позволяет объявление типа переменной i, в нашем случае это char в большинстве компиляторов по-умолчанию это без знаковый символьный тип - он может хранить числа от 0 до 255 i < 20 - контрольное выражение Может быть с разными операторами отношения, важно лишь чтобы по ходу цикла оно становилось когда-то "ложью" - иначе цикл "зациклится" т.е. ни когда не кончится.

i += 4 - это счетчик или изменение переменной цикла. Обычно это i++ т.е.к переменной добавляется 1 каждый "прогон" цикла. Но опять же может быть таким какое вам требуется.

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

i =(7 + i*4) или i = (функция других переменных)

<source lang="c"> Циклы for(;;) и while()

часто используют вот так:

while(1);

for (;;);

/* Так написанные эти циклы означают :

МК выполнять эту строчку пока есть питание, нет сброса и нет прерывания. Когда возникает прерывание, программа переходит на обработчик прерывания и (если в обработчике нет перехода в другое место программы) по завершении кода обработчика опять возвращается в такой цикл. */

while(1){ код программы };

for (;;){ код программы };

/* Так написанные эти циклы означают :

МК выполнять код программы пока есть питание, нет сброса и нет прерывания. Когда возникает прерывание, программа переходит на обработчик прерывания и (если в обработчике нет перехода в другое место программы) по завершении кода обработчика опять возвращается сюда и продолжает выполнять код программы */ </source>

8)switch(){ }; - оператор множественного выбора,

позволяет вам сделать выбор из нескольких вариантов. <source lang="c"> switch (выражение) { case 5: код на Си /* этот код будет выполняться если результат вычисления выражения равен числу 5

на этом работа оператора switch закончится */ break;

case -32: код на Си /* этот код будет выполняться если результат вычисления выражения равен отрицательномц числу -32

на этом работа оператора switch закончится */ break;

case 'G': код на Си /* этот код будет выполняться если результат вычисления выражения равен числу соответствующему символу G в таблице ASCII

на этом работа оператора switch закончится */ break;

default: код на Си /* этот код будет выполняться если результат вычисления выражения не равен ни 5 ни -32 ни 'G'

А так же после выполнения кода не имеющего в конце break;

на этом работа оператора switch закончится */ };

/* switch закончен - выполняется дальнейший код программы */ </source>

case 
- может быть столько сколько вам нужно, чтобы программа работала быстрее старайтесь наиболее вероятные варианты располагать выше!
default 
- не обязателен. Его можно расположить и не в конце.
break; 
- если его не использовать то найдя нужный вариант программа будет выполнять и следующие ниже условия case

[Прочитайтеподробней о switch с примерами.

[Скачайте и распечатайте таблицу символов ASCII на ОДНОЙ странице!

9) goto - оператор безусловного (немедленного) перехода. <source lang="C"> ... какой-то код нашей программы на Си ...

mesto_5: /* сюда мы попадем после выполнения строки программы goto mesto_5 */

   код будет выполнятся после goto mesto_5;

... какой-то код нашей программы на Си ...

mesto_1: /* сюда мы попадем после выполнения строки программы goto mesto_1 */

   код будет выполнятся после goto mesto_1;

... какой-то код нашей программы на Си ...

goto mesto_1; /* перейти в то место программы где в начале строки написано mesto_1: */

... какой-то код нашей программы на Си ...

goto mesto_5; /* перейти в то место программы где в начале строки написано mesto_5: */

... какой-то код нашей программы на Си ... </source>



Используйте goto с осторожностью! Думайте к чему может привести выполнение функций или конструкций вашей программы не до конца.

CVAVR помогает вам в контроле не позволяя где угодно втыкать goto


	Оператор Си   ?   работает почти как  if - вот так: 

Пример функция в которую передается значение переменной val_d

Вызов функции и передач в нее числа хранящегося в переменной с именем peremennaya

resultat = funkziya(peremennaya);


В функции число из peremennaya будет помещено в val_d и обработано.

int funkziya(int val_d) {

 return ((val_d>511)?(-1024+val_d):(val_d));

}

( (выражение) ? ( если выражение истина ) : ( если выражение ложно ) )

если val_d>511 то функция возвратит val_d уменьшенное на 1024

если val_d=<511 то функция возвратит val_d не меняя его.

Возвращаемое функцией значение val_d будет помещено в переменную в строке вызова функции - resultat

Подробнее о функциях будет написано ниже.


Ну вот - ПОЧТИ всё что нужно нам из Си !


Как использовать описанное выше вы можете посмотреть в примерах к компилятору !

Примеры в папке :

C:\CVAVR\EXAMPLES

Открывайте файлы исходников .с и разбирайте текст программ - что делает каждая строчка кода !

Это великолепный способ само-обучения программированию !

Новичку понадобятся для понимания программ написанных профи :

Указатели, Структуры и Союзы.

Прочитайте о них в он-лайн книгах по Си которые расположены ниже на страничке. Примеры применения указателей, структур и союзов в разных компиляторах вы найдете в FAQ к курсу по AVR - скачайте и читайте.

Структура программы на языке Си.

Программа на языке Си это текстовый файл, обычно с расширением .c

Текст программы называют исходным или "исходником" или "сурцом" от анг. source code - это вам ключевые слова для поиска

Весь исполняемый код программы на Си находится в функциях - т.е. в фигурных скобках { исполняемый код программы }


Программа на Си имеет определенную структуру :

1) заголовок

2) включение необходимых внешних файлов - #include

3) ваши определения для удобства работы - #define

4) объявление глобальных переменных и констант

   Глобальные переменные и константы   

- объявляются вне какой либо функции.

   т.е. не после фигурной скобки   {

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

5) описание функций - обработчиков прерываний

6) описание других функций используемых в программе

7) функция main <- это единственный обязательный пункт !


Это не жесткий порядок а ориентировочный !

Иногда п.6 это прототипы функций, а сами функции описываются полностью после п.7

Прототип функции - показывает образец того как применять функцию в программе, какие значения в нее передаются и если она возвращает какое-то значение то прототип указывает тип возвращаемых данных. Прототип не имеет скобок { } а после скобок ( ) ставится  ;

Функция - имеет { "тело" } в фигурных скобках. Тело это код на Си определяющий то что делает функция.

после вызова функции не ставится !

Программа на Си начинает работу с функции main()

по необходимости из main()вызываются другие функции программы, из которых может быть вызов следующих функций, по завершении работы функции программа возвращается по той же цепочке как вызывались функции. <source lang="C"> main(){

... какой то код программы ...

вызов функции_1; //программа перейдет в функцию_1

строка программы; // будет выполнятся после

                 // возврата из функции_1 

... какой то код программы ...

} </source> На странице 3. "Прерывания в AVR" - вы уже читали, что описанный выше ход программы может нарушаться прерываниями.




Пример программы на Си

с описанной выше структурой я буду писать на голубом фоне.

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

Ниже будет написан пример ОДНОЙ программы на Си.

<source lang="C">

	/* пункт 1   заголовок программы 

Он оформляется как комментарий, и обычно содержит информацию

- о названии, назначении, версии и авторе программы - краткое описание алгоритма программы - пояснения о назначении выводов МК и режиме его работы, фьюзы - компилятор, инструменты и их версии - другие сведения которые вы считает полезным указать

  • /

// комментарий после двух косых черт пишут в одну строку!


// пункт 2 включение внешних файлов

  1. include <mega16.h> /* перед компиляцией, препроцессор компилятора вставит вместо этой строчки содержимое (текст) заголовочного файла "хидера" mega16.h - этот файл содержит перечень регистров имеющихся в МК ATmega16 и соответствие их названий их физическим адресам в МК.

Посмотрите его содержание !!!

CVAVR\inc\mega16.h

Не забывайте указать какой МК вы используете в свойствах проекта в компиляторе */


//delay functions

  1. include <delay.h>

/* перед компиляцией, препроцессор компилятора вставит вместо этой строчки текст "хидера" delay.h - этот файл содержит функции для создания пауз в программе.

Теперь чтобы сделать паузу вам нужно лишь написать : */

delay_us(N); /* сделать паузу N (число) микроСек это должна быть константа - НЕ переменная !!! например delay_us(12 + 7*3); например delay_us(117); */

delay_ms(x); /* сделать паузу x милиСек x - может быть переменная, выражение или число от 0 до 65535 (тип unsigned int) например delay_ms(3280); например delay_ms(переменная); например delay_ms(переменная*4 + 760); */


// пункт 3 определения пользователя

// AD7896 control signals PORTB bit allocation

  1. define ADC_BUSY PINB.0
  2. define NCONVST PORTB.1

/* после этих двух строк, перед компиляцией, препроцессор компилятора заменит в тексте программы ADC_BUSY на PINB.0 и NCONVST на PORTB.1 <source lang="C"> Таким образом вместо того что бы помнить что вывод занятости AD7896 подключен у вас к ножке PB0 вы можете проверять значение осмысленного понятия ADC_BUSY - "АЦП занят"

а вместо управления абстрактной ножкой PB1 (через PORTB.1) вы можете управлять "НьюКонвешнСтат" - NCONVST - "стартовать новое АЦ преобразование" <source lang="C">

  1. define - Это удобно ! Но ВОВСЕ не обязательно.
  • /
  1. define INIT_TIMER0 TCNT0=0x100L-F_XTAL/64L/500L

/* этот пример показывает что определения могут быть и сложней ! */ </source>

  1. define - может содержать и некоторые переменные, вместо которых в тексте программы могут быть подставлены и числа и слова. Может определять даже сложные, полноценные функции.

Например:

  1. define invbit(p,n) (p=p^bit(n))

Здесь переменные величины это 'p' и 'n'. Теперь для инвертирования бита 5 в регистре PORTB вам достаточно написать в программе:

invbit(PORTB,5);

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

Примеры #define есть в FAQ к курсу.

Определения БИТ-ов AVR (соответствие номера бита в регистре его названию по ДШ) есть в "хидерах" .h в компиляторах ICC, IAR, WinAVR и других компиляторах,

Но их нет в хидерах CodeVisionAVR - это не позволяет напрямую вставлять в текст программы примеры кода из даташит МК

Поэтому я сделал для вас файл - заголовок m8_128.h содержащий определения битов некоторых AVR.

Скачайте его и добавьте в программу вот так:

(Если вы читаете курс с начала и делаете то, что предлагается то этот файл у вас уже есть). <source lang="C">

  1. include <mega16.h>

/* сперва обычный "хидер"-заголовок для МК

  используемого в вашей программе */
  1. include <m8_128.h>

/* затем мой "хидер"-заголовок с определениями

  названий и номеров битов для используемого МК */

</source>

Теперь вы можете использовать примеры на Си из ДШ на ваш МК !

Мой файл m8 128.h содержит определения битов для микроконтроллеров ATmega8 ATmega16 ATmega32 ATmega64 ATmega128


Для всех AVR определения битов есть в .h заголовках WinAVR вот архив (127 Кб) скачайте и используйте если понадобится.


Мастер начального кода программы в компиляторе ICC умеет по вашему желанию автоматически делать

  1. define для ножек для ножек МК !

Подробней про это и с картинкой смотри в соответствующей задаче курса.

Пункт 4.

Объявление переменных

Перед использованием переменной в программе на Си её необходимо объявить - т.е. указать компилятору какой тип данных она может хранить и как она называется.

Наиболее подробно об этом по ссылке:

1.2. ТИПЫ ДАННЫХ И ИХ ОБ ЯВЛЕНИЕ

Ниже сжато - самое главное:

Формат объявления переменной таков:

[<storage modifier>] <type definition> <identifier>;


[<storage modifier>]
- необязательный элемент,

он нужен толон нужен только в некоторых случаях и может быть:

extern 
- если переменная может использоваться в других файлах исходного кода программы, например объявляется во внешнем файле - хидере delay.h приведенном выше, а используется в основном файле программы.
volatile 
- ставьте если нужно предотвратить возможность повреждения содержимого переменной в прерывании, и не позволить компилятору попытаться выкинуть её при оптимизации кода.

Ставьте всегда если не знаете точно - нужно или нет !

пример:

volatile unsigned char x;


static 
- если переменная локальная т.е. объявлена в какой либо функции после скобки { и должна сохранять свое значение до следующего вызова этой функции.
register 
- разместить переменную в регистрах AVR - это может ускорить доступ к ней. CVAVR по-умолчанию размещает переменные в регистрах до их заполнения. Но размещение переменных в регистрах делает их не видимыми при отладке в PROTEUS.
eeprom 
- разместить переменную в EEPROM. Это энергонезависимая память - значение таких переменных сохраняется при выключении питания и при перезагрузке МК.

пример: eeprom unsigned int x;

Если это первая переменная в EEPROM то её младший байт будет помещен в ячейку 1 EEPROM а старший в ячейку 2. Ячейка 0 не используется так как рекомендует производитель. CVAVR похоже не использует и 0 и 1 ячейки EEPROM. Необходимо помнить что запись в EEPROM длительный процесс - по таблице "Table 1. EEPROM Programming Time" это 8500 тактов процессора.

Количество записей в ячейки EEPROM ограничено !

Подробней в "Accessing the AVR internal EEPROM".

Книги и учебники по радиоэлектронике и микроконтроллерам там

Скачать весь курс по AVR одним архивом


Глобальные переменные объявляются до появления их в тексте какой либо функции. После объявления, глобальные переменные доступны в любой функции программы.

Локальные переменные объявляются в самом начале функций - т.е. сразу после фигурной скобки {

Локальные переменные доступны только в той функции где они объявлены! В разных функциях могут быть объявлены локальные переменные с одинаковыми именами - я не советую вам так делать.

Советую не использовать ЛОКАЛЬНЫЕ переменные в главной функции main.


<source lang="C"> <type definition> - тип данных которые может хранить переменная.

наиболе часто используемые типы данных :

unsigned char - хранит числа от 0 до 255 (байт)

unsigned int - хранит числа от 0 до 65535 (слово == 2 байта)

unsigned long int - хранит от 0 до 4294967295 (двойное слово == 4 байта) </source>

Подробнее все типы данных посмотрите в Help

CVAVR\bin\CVAVR.HLP

Раздел "Data Types"

Уточняйте ТИПЫ данных в руководстве к вашему компилятору !

Вместо unsigned char - можно писать писать просто char, так как компилятор по-умолчанию считает char без знаковым байтом.

А если вам нужен знаковый байт то объявляйте его так :

signed char imya_peremennoi;

<identifier> - имя переменной - некоторый набор символов по вашему желанию, но не образующий зарезервированные слова языка Си.

Выше был уже пример идентификатора - имени переменной: imya_peremennoi


Давайте осмысленные имена переменным и функциям - напоминающие, "говорящие" вам об их назначении.

Принято использовать маленькие буквы, а для отличия имен переменных от названия функций - имена переменных можно например начинать с буквы, а названия функций (кроме main конечно) с символа подчеркивания.

Например так :

 moya_peremennaya        _vasha_funkziya 	 

Внимание!

Глобальные переменные, а также локальные с модификатором static - при старте и рестарте программы равны 0 если вы не присвоили им (например оператором =) иное значение при их объявлении или по ходу программы.


Подробные примеры объявления переменных посмотрите пожалуйста в разделе Variables в "Хелп" компилятора CVAVR.


Вот несколько примеров объявления переменных :

unsigned char my_peremen = 34; unsigned int big_peremen = 34034;

Это объявлены две переменные и им присвоены значения.

Первая my_peremen - символьного типа - это 1 байт, она может хранить число от 0 до 255. В данном случае в ней хранится число 34.

Вторая big_peremen - целого типа, два байта, в ней может хранится число от 0 до 65535 , а в примере в неё поместили десятичное число 34034.


Пример массива содержащего 3 числа или элемента массива.

char mas[3]={11,22,33};

Нумерация элементов начинается с 0. Т.е. элементы данного массива называются

mas[0], mas[1], mas[2]

и в них хранятся десятичные числа 11, 22 и 33.

Где то в программе вы можете написать:

mas[1] = 210;

Теперь в mas[1] будет хранится число 210

- массивы могут быть многомерными, - можно не присваивать значений элементам

  массива при объявлении.

НО только при объявлении вы можете присвоить значения всем элементам массива сразу ! Потом это можно будет сделать только индивидуально для каждого элемента.


Строковая переменная или массив содержащий строку символов.

char stroka[6]="Hello";

Символов (букв) между кавычками 5 , а я указал размер строки 6  !

Дело в том, что строки символов должны заканчиваться десятичным числом 0.

Не путайте его с символом '0' которому соответствует десятичное число 48 по таблице ASCII - которая устанавливает каждому числу определенный символ.

Например :

Элемент строки stroka[1] содержит число 101 которому по таблице ASCII соответствует символ 'e'

Элемент stroka[4] содержит число 111 которому соответствует символ 'o'

Элемент stroka[5] содержит число 0 которому соответствует символ 'NUL' его еще обозначают вот так '\0'

Строковая переменная может быть "распечатана" или выведена в USART MK вот так:

printf("%s\n", stroka);

Вы можете преобразовать строковую переменную в число! Если исходная строка символов такая  :

char stroka[]="3654694"; то вот так:

perem_1 = atoi(stroka);

мы поместим в переменную perem_1 (которую должны были ранее в программе объявить как "беззнаковую целую") число 36546. Это число влезет в переменную perem_1 которая может хранить числа от 0 до 65535. А вот 9 и 4 уже не поместятся. Для бОльших чисел есть функция - atol() Чтобы использовать эти функции необходимо включить в начале программы заголовочный файл :

  1. include <stdlib.h>


Для преобразования числа в строку

есть itoa() и ltoa()

и аналогичные функции для чисел с плавающей точкой.

Подробнее об этих и других полезных функциях смотрите раздел "Standard Library Functions" справки компилятора CodeVisionAVR.

Советую вам скачать заголовочный файл

m8 128.h

Он содержит названия битов МК ATmega8 -16 -32 -64 -128 и сокращенные названия типов данных как в компиляторе IAR.

вот отрывок из него: <source lang="C">

  1. define u8 unsigned char // 0 to 255
  2. define s8 signed char // -128 to 127
  1. define u16 unsigned int // 0 to 65535
  2. define s16 signed int // -32768 to 32767
  1. define u32 unsigned long int

// 0 to 4294967295

  1. define s32 signed long int

// -2147483648 to 2147483647

  1. define f32 float // ±1.175e-38 to ±3.402e38
  2. define d32 double // ±1.175e-38 to ±3.402e38

</source>

После включения моего "хидера" в текст вашей программы вы сможете писать вместо длинного

unsigned long int <имя 32 битной переменной>

коротко :

u32 <имя 32 битной переменной>

u - без знаковая - значит не отрицательная
s - значит переменная со знаком 

32 - количество бит в переменной


КОНСТАНТЫ.

flash и const ставятся перед объявлением констант - неизменяемых данных хранящихся во флэш памяти программ. Они позволяют вам использовать не занятую программой память МК. Обычно для хранения строковых данных - различные информационные сообщения, либо чисел и массивов чисел.

КОНСТАНТЫ ПРИМЕРЫ из CVAVR help <source lang="C"> flash int integer_constant=1234+5; flash char char_constant=’a’; flash long long_int_constant1=99L; flash long long_int_constant2=0x10000000; flash int integer_array1[ ]={1,2,3}; flash int integer_array2[10]={1,2}; flash int multidim_array[2][3]={{1,2,3},{4,5,6}}; flash char string_constant1[ ]=”This is a string constant”;

const char string_constant2[ ]=”This is also a string constant”; </source> В других компиляторах могут быть отличия !





Следующий пункт в структуре программы на Си для МК <source lang="C"> пункт 5

Описание функций-обработчиков прерываний.


Механизм прерываний подробно описан на странице 3 - Прерывания в AVR

	/* 

Конкретно в ЭТОЙ программе - есть только одно прерывание и значит одна функция обработчик прерывания.

Программа будет переходить на неё при возникновении прерывания :

ADC_INT - по событию "окончание АЦ преобразования"

  • /

interrupt [ADC_INT] void adc_isr(void) { PORTB=(unsigned char) (~(ADCW>>2)); /* отобразить горящими светодиодами подключенными от + питания МК через резисторы 560 Ом к ножкам порта_B старшие 8 бит результата аналого-цифрового преобразования

Сделаем паузу 127 мСек - просто как пример пауз */ delay_ms(127);


/*

В реальных программах старайтесь не делать пауз в прерываниях !

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

Например - в обработчике прерывания вы только устанавливаете флаги (биты или переменная) означающие состояние кнопок, значения переменных или регистров, а обрабатываете это уже в основном цикле программы, через конструкции if - else или switch (описаны выше!)

  • /

// начать новое АЦПреобразование ADCSRA|=0x40;

} // закрывающая скобка обработчика прерывания </source>


Функция обработчик прерывания может быть названа вами произвольно - как и любая функция кроме main.

Здесь она названа : adc_isr


При каком прерывании ее вызывать - компилятор узнает из строчки :

interrupt[ADC_INT]

по первому зарезервированному слову - interrupt - он узнаёт, что речь идет об обработчике прерывания,

а номер вектора прерывания (адрес куда физически, внутри МК перескочит программа при возникновении прерывания) будет подставлен вместо ADC_INT препроцессором компилятора перед компиляцией - этот номер указан в подключенном нами ранее заголовочном файле ("хидере") описания "железа" МК - mega16.h - это число сопоставленное слову ADC_INT. Не ленитесь, посмотрите в файле !



Очень информативна и тем ценна для обучающегося следующая строка программы:

PORTB = (unsigned char) (~(ADCW >> 2));


Давайте проанализируем как она работает.

= оператор присваивания. Он означает присвоить значение вычисления выражения справа от оператора присваивания той переменной что указана слева от него.

Значит нужно вычислить выражение справа и поместить его в переменную PORTB.

Вычислим что справа от оператора присваивания.

ADCW - это переменная слово (двухбайтовая величина - так она объявлена в файле mega16.h) в котором CodeVisionAVR сохраняет 10-битный результат АЦП - а именно в битах9_0 (биты с 9-го по 0-й) т.е. результат выровнен обычно - вправо.


VMLAB имеет только 8 светодиодов - значит нужно отобразить 8 старших бит результата - т.е. биты_9_2 - для этого мы сдвигаем все биты слова ADCW вправо на 2 позиции

ADCW >> 2 /* биты 1 и 0 вылетают вправо из числа в небытие, бит_9 перемещается в позицию бит_7, бит_8 в позицию бит_6 и так далее до бит_2 становится бит_0 */

Теперь старшие 8 бит результата АЦП встали в биты7_0 младшего байта (LowByte - LB) слова ADCW

	>> n 	означает сдвинуть все биты числа вправо на n  позиций 

это равносильно делению на 2 в сепени n

	<< n 	

означает сдвинуть все биты числа влево на n позиций это равносильно умножению на 2 в сепени n


Сдвиг используется очень часто !


Светодиоды подключены так как написано выше - т.е. подключены правильно !

Загораются (показывая "1") при "0" на соответствующем выводе МК - значит нам нужно выводить в PORTB число в котором "1" заменены "0" и наоборот - это делает как я рассказал выше:

~ операция побитного инвертирования - меняет значения битов.

Значит результатом этого выражения

~(ADCW >> 2)

будут инвертированные 8 старших бит результата АЦП находящиеся в младшем (правом - LB) байте двух байтового слова ADCW


Выше я уже говорил что :

в Си в переменную можно помещать только тот тип данных который она может хранить !


Так как PORTB это байт, а ADCW - это два байта, то прежде чем выполнить оператор присваивания (это знак = ) нужно преобразовать слово (слово - word - значит два байта) ADCW в без знаковый байт.

	Преобразование типов данных - делают так : 

перед тем что надо преобразовать записывают в скобках ( ) тип данных к которому нужно преобразовать.

Пишем ...

(unsigned char) (~(ADCW>>2))

Результат этой строки - один байт и мы можем поместить его в PORTB


Если в регистре DDRB все биты равны "1" - т.е. все ножки порта_B выходы, мы безусловно увидим старшие 8 бит результата АЦП горящими светодиодами.


Вам должна быть абсолютно понятна разобранная строка:

PORTB = (unsigned char) (~(ADCW>>2));


Если это не так то

повторите разбор, и перечитайте материал по Си по использованным операторам Си.


Разберем еще одну строчку

ADCSRA|=0x40;

Обратите внимание на необходимость ставить в конце выражений точку с запятой - не забывайте !

Эта строка означает следующее:

Двигаемся слева на право :

- берем значение переменной ADCSRA (это регистр МК - значит программа прочитает его, возьмет число из него)

- выполняем с этим числом операцию обозначаемую вертикальной черточкой | ( это поразрядная операция ИЛИ - только "0" и "0" дают "0" ) с числом 0x40

- присвоим или поместим результат поразрядного ИЛИ обратно в переменную ADCSRA - т.е. запишем результат в регистр ADCSRA

0x40 это в двоичном виде: 0100 0000

так как в результате поразрядного ИЛИ только два "0" дают "0" биты в ADCSRA напротив нулей не изменятся, а вот бит_6 в ADCSRA оказывается напротив "1" и теперь он станет "1" не зависимо от того каким он был до этого !

т.е. смысл рассматриваемой строки программы

ADCSRA|=0x40;

"установить" (т.е. сделать "1") бит_6 в регистре ADCSRA


Число справа от составных операторов |= &= ^= обычно называют маской,

и говорят "наложить маску" - так как в результате меняются лишь те биты которые нужно изменить.

Управление отдельными битами в переменной или регистре.

Как изменить только некоторые биты не изменяя остальные.

Для обнуления нужных бит используют обозначаемое знаком & поразрядное логическое И - только "1" и "1" дает "1"

PEREM &=(~0x04); // обнулить бит_2 в переменной PEREM Скобки здесь я добавил для улучшения читаемости кода.


Самоконтроль - важно:

а) обязательно разберитесь почему обнуляется бит_2

б) Как в двоичном виде выглядит результат (~0x04)


А вот так более понятно:

 PEREM &=(~(1 << 2)); // обнулить бит_2 в переменной PEREM


Обнулить биты 5, 3 и 0 в переменной PEREM

 PEREM &=(~ (  (1 << 5)|(1 << 3)|(1 << 0)  ) );

конечно здесь вместо (1 << 0) можно написать просто (1)


"Установить" - сделать "1" - биты 7, 5 и 3 в переменной PEREM

 PEREM |=(1 << 7)|(1 << 5)|(1 << 3);


Обязательно разберитесь как это работает - вы должны это понимать и ГЛАВНОЕ использовать в своих программах.

Например (1 << 4) означает: взять число 1 и все его биты сдвинуть в лево на 4 позиции - в итоге мы получим двоичное 10000. Эти вычисления компилятор сделает сам и в программе заменит всё, что правее = на число-результат.

Вместо номеров битов вы можете использовать их названия из даташит. Но в CVAVR для этого надо включить мой заголовок о котором написано выше или самому сделать определения битов из архива выложеного выше. А в IAR надо отметить галочку "Элау бит дефинишнс" в свойствах проекта.

 WDTCR |= (1 << WDTOE) | (1 << WDE);

эта строка программы "Установит" - сделает "1" биты WDTOE и WDE в регистре WDTCR


<source lang="C">

	 /* Пункт 6      Функции используемые в программе   */

// их может быть столько сколько вам нужно.

// у нас будет одна, кроме main и // обработчика прерывания.

/* =================================

Это будет функция в которой описано начальное конфигурирование МК в соответствии с поставленной задачей

Удобно над функцией сделать заголовок подробно поясняющий назначение функции !

===================================== */

(void)_init_mk(void) { /* Вначале любой функции объявляются ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ - если конечно они вам нужны */

/* void - означает пусто.

Перед названием функции - void - означает что функция не возвращает ни какого значения. А в скобках после названия означает что при вызове в функцию не передаются ни какие значения. */

// инициализация Port_B DDRB=0xFF; // все ножки сделать выходами PORTB=0xFF; // вывести на все ножки "1"


/* настройка АЦП - производится записью определенного числа в регистр "ADC Control and Status Register A" – ADCSRA

посмотрите его описание в ДШ МК мега16.

Нам нужно:

- Включить модуль АЦП

- Установить допустимую частоту тактирования АЦП при частоте кварца 3.69 МГц - мы выберем коэф. деления 64 - это даст частоту такта для процессов в АЦП 57.656 КГц

- Включить прерывание по завершению АЦ преобразования.

По ДШ для этого нужно записать в регистр ADCSRA число: 1000 1110 или 0х8E */

// ADC initialization w Oscillator=3.69MHz // ADC Clock frequency: 57.656 kHz // ADC Interrupts: On ADCSRA=0x8E;


/* Теперь выбираем вход АЦП ADC0 (ножка PA0) и внешнее опорное напряжение (это напряжение код АЦП которого будет 1023) с ножки AREF

Смотрим что нужно записать для этого в регистр мультиплексора (выбора входа) АЦП ADMUX

см. ДШ */

// Нужно записать 0 (он там по-умолчанию) ADMUX=0;


/* Разрешаем ГЛОБАЛЬНО все прерывания

     разрешенные индивидуально ! 

Вы наверно поняли что индивидуально мы разрешили лишь прерывание по завершении АЦП - вот оно то и сможет возникать у нас. */

  1. asm("sei")

</source>

Внимание !

Так делаются Ассемблерные вставки в CVAVR :

  1. asm ("инструкция на ассемблере")

Обратите внимание - точки с запятой в конце НЕТ ! Такие вставки принято иногда делать. НО они не являются необходимыми.

На языке Си можно управлять ВСЕМИ программно изменяемыми битами в регистрах МК !


	Напоминаю ...    

Все регистры МК перечислены в таблице в конце ДШ с указанием номеров страниц с подробным описанием регистра и его битов.

Часто используются такие ассемблерные вставки : <source lang="C">

  1. asm("sei") // Разрешить ГЛОБАЛЬНО все прерывания
  1. asm("cli") // Запретить ГЛОБАЛЬНО все прерывания
  1. asm("nop") // Пауза в 1 такт процессора
  1. asm("wdr") // Сбросить сторожевой таймер


	// все функция закончена

} // скобка закрывающая для функции _init_mk()

Далее...

	/* 
  Пункт 7       Главная функция  main()  -  обязательная ! 
  • /

/* ================================= Главная функция -

Си программа начинает выполнятся с нее!

===================================== */

void main(void){ /* Вначале любой функции объявляются

  (если нужны)  ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ  */

_init_mk();/*Вызываем функцию инициализации, настроийки аппаратуры МК. Выполнив ее программа вернется сюда и будет выполнять следующую строку */

// запускаем первое АЦП ADCSRA|=0x40;

// бесконечный цикл в ожидании прерываний while(1); /* Программа будет крутится на этой строчке постоянно проверяя истинно ли условие в скобках после while а так как там константа 1 - то условие будет истинно всегда!

 // функция main закончена

} // скобка закрывающая для функции main() </source>



Эта программа на Си будет работать так :

По завершении АЦП будет возникать прерывание и программа будет перескакивать в функцию обработчик прерывания adc_isr()

При этом будут автоматически запрещены все прерывания ГЛОБАЛЬНО !

В конце adc_isr() запускается новое АЦ преобразование и при выходе из обработчика прерывания снова разрешаются глобально прерывания, и программа возвращается опять в бесконечный цикл while(1)

Такая чехарда будет продолжаться пока есть питание МК и не будет сброса.

Светодиоды будут высвечивать 8-ми битный код АЦП напряжения на ножке PA0

Всё - программа на Си написана и разобрана.

Вам должно быть все ясно и абсолютно понятно!

Если это не так то перечитайте, подумайте, повторите разбор, почитайте рекомендованное ниже по Си.

Еще щепотка Си :

Пример:

делать что-то пока на ножке PBn есть "1"

Как AVR переводит напряжения на выводах МК в логические уровни - рассказано с картинками, графиками на 2странице 2 курса - Устройство микроконтроллера AVR. <source lang="C"> while(PINB & (1 << n)){ // для любого компилятора

            Какой-то код программы    

/* Какой-то код будет выполнятся снова и снова, пока проверка условия в скобках после while будет давать "истину" - значит пока на ножке PBn есть логическая единица

Проверка условия выполняется в начале и затем каждый раз по завершении выполнения какого-то кода

Пока выполняется какой-то код проверка того что на ножке PBn не производится. */

                                             };

примечание - в CVAVR можно написать проще while(PINB.n){ // но для регистров с адресом до 31


Пример: выполнить что-то если на ножке PCn есть "0"

if((~PINC)&(1 << n)){ // для любого компилятора

                    что-то
/* что-то начнет выполняться если на ножке PCn "0" */
                   };

примечание - в CVAVR можно написать проще if(!(PINC.n)){


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

Примечание - Условие :

if((~PINC)&(1 << n)) {

можно записать и вот так :

if(!(PINC & (1 << n))) {


Пример: выполнить что-то если на ножке PBn есть "1"

if((PINB)&(1 << n)){ // для любого компилятора

                    что-то
/* что-то начнет выполняться если на ножке PBn "1" */
                   };

примечание - в CVAVR можно написать проще if(PINB.n){ </source> К битам регистров с адресами от 0 до 31 в компиляторе CodeVisionAVR можно обратится (и читать и записывать) проще.

Вот так: REGISTR.BIT

Пример: <source lang="C"> PINB.2 или PORTA.5 или DDRC.7 </source> Пример: <source lang="C"> if(!PINB.2){

               этот код /* Если на ножке PB2 низкий 

логический уровень - то выполнить этот код */

          };   

Пример: PORTA.3 = 1; /* Сделать бит 3 в регистре PORTA единицей - говорят: "установить бит" по англ. "set bit" */

Пример: PORTB.6 = 0; /* Сделать бит 6 в регистре PORTB нулем - говорят: "очистить, сбросить бит" по англ. "clear bit" */ </source>

Битовые операции подробно описаны в задаче 1

и конечно в справке - help - компиляторов !

Теперь вы должны знать

- как записать число в регистр, в переменную

- как изменить бит в регистре

- как взять число из регистра

- как выполнить что-то в зависимости от

 значения бита в регистре или в переменной

- записывайте возникающие вопросы !

   и лучше на бумагу - моторная память !

- найдите в DataSheet (ДШ) регистры и устройства МК использованные в задаче, прочитайте о них подробней.

- если вопросы остались перечитайте задачу снова !

- если вопросы не разрешены, ищите ответ:

1) в help и документации компилятора, симулятора, других используемых программ!

2) поиском Windows в папках и help компилятора и симулятора.

3) поиском Windows в папке где сохранен у вас курс.

4) в моем не структурированном мини-AVRFAQ - это сборник ответов на часто задаваемые мне по курсу вопросы и советы по применению МК от знающих людей.


Дальше - страница 6

Задачи - Упражнения Курса Практическая работа с Компилятором с Симулятором с МК и внешними устройствами


--Nekolex 20:47, 27 сентября 2009 (UTC)