Клуб "Трёх инженеров"
 

Email:

Пароль:

Забыли пароль?

Вступить в клуб?

Микроконтроллеры AVR

MS Visual Studio & C#

MODBUS-RTU & RS485

SolidWorks & Cosmos

Компьютерная техника

Мехатроника & Авиация

Силовая электроника

Всего статей:

Категорий/рубрик:

Комментариев:

Пользователей:

33

7

239

2029

 
видео прикол из Городка
Репортаж об интернете из глубинки
Для корректного отображения этого элемента вам необходимо установить FlashPlayer и включить в браузере Java Script.

Модуль АЦП-8бит на МК ATmega8535. Часть 2 – Прошивка микроконтроллера

Автор: Рудаков Г. В.

Дата: 2009-11-09


Продолжаем проект по созданию измерительного устройства АЦП модуля на микроконтроллере AVR. После того как была спроектирована принципиальная электрическая схема и печатная плата, требуется написать прошивку (микропрограмму) для микроконтроллера. Этим и займемся в данной статье.

Итак, в качестве редактора и компилятора я выбрал студию CodeVisionAVR за её многофункциональность, большое количество встроенных библиотек и присутствие генератора кода.

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

Окно CodeWizardAVR. Выбор МК.

Рисунок 1 – Окно CodeWizardAVR.
Выбор МК.

Первым делом укажем желаемый чип. В нашем случае это ATmega8535 (выбор данного микроконтроллера был обоснован в первой части статьи).

Затем переходим на вкладку «Timers». Здесь нас интересует инициализация таймера под номером 0. Выставляем значение частоты, то есть параметр «Clock Value» = 125 кГц (рисунок 2). Данное число берется не с потолка, а по рекомендациям из документации на МК. Производитель утверждает, что наибольшая точность преобразования достигается, если тактовая частота модуля АЦП находится в диапазоне 50…200 кГц.

 Окно CodeWizardAVR. Инициализация таймера.

Рисунок 2 – Окно CodeWizardAVR.
Инициализация таймера.

Еще нам понадобится прерывание по переполнению таймера, поэтому ставим галочку «Overflow Interrupt». Параметр «Timer Value» пока не заполняем, его будем реинициализировать позже.

Переходим во вкладку «ADC – Analog to Digit Converter» (рисунок 3). Ставим галочки напротив «ADC Enabled» и «Interrupt». Выбираем частоту АЦП модуля равную частоте таймера (125 кГц), инициализацию которого выполнили раньше.

Окно CodeWizardAVR. Инициализация АЦП.

Рисунок 3 – Окно CodeWizardAVR.
Инициализация АЦП.

И, выставляем значение параметра «Volt. Ref» - внутренний источник опорного напряжения с внешним конденсатором на ножке AREF. На данном этапе по инициализации АЦП модуля микроконтроллера это все. Позже вручную допишем еще несколько параметров (состояний регистров).

Теперь настроим LCD-дисплей. Его инициализации представлена на рисунке 4.

Окно CodeWizardAVR. Инициализация LCD-дисплея.

Рисунок 4 – Окно CodeWizardAVR.
Инициализация LCD-дисплея.

На рисунке 4 видим, что программа автоматически в соответствие с кодом ее библиотеки, выдала нам требуемую «распиновку» для порта «С». Не забываем указать число символов в применяемом LCD-дисплее – это 8 символов в строке.

Следующим шагом настроим шину 1-Wire, используемую для подключения датчика температуры окружающей среды DS1820 (рисунок 5). Здесь требуется лишь указать используемый порт и номер ножки этого порта.

Окно CodeWizardAVR. Инициализация шины 1-Wire.

Рисунок 5 – Окно CodeWizardAVR.
Инициализация шины 1-Wire.

И, в завершение инициализации, необходимо произвести настройку универсального синхро-асинхронного передатчика, коротко называемого USART (в нашем случае это всего лишь UART, так как синхронизация не используется, полагаемся на точность работы кварцевого резонатора). Он необходим для передачи произведенных аналогово-цифровых преобразований на ПК. Смотрим рисунок 6.

Окно CodeWizardAVR. Инициализация USART.

Рисунок 6 – Окно CodeWizardAVR.
Инициализация USART.

Активируем галочки «Receiver» и «Transmitter» для возможности пользоваться и приемником и передатчиком. Чтобы посланные модулю команды с ПК не потерялись, активируем «Rx Interrupt» (прерывание по приему) с размером буфера в 8 символов.

Вроде все. Остальные настройки подправим ручками. Теперь сохраняем настройки и генерируем код (рисунок 7).

Окно CodeWizardAVR. Сохраняем настройки и генерируем программный код.

Рисунок 7 – Окно CodeWizardAVR.
Сохраняем настройки и генерируем программный код.

Перед тем как перейти к комментированию получившегося программного кода сгенерированного CodeWizardAVR и дальнейшему написание остальной части микропрограммы для разрабатываемого модуля, рассмотрим составленный алгоритм «прошивки», представленный на рисунке 8.

Алгоритм микропрограммы («прошивки» МК)

Рисунок 8 – Алгоритм микропрограммы («прошивки» МК).

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

Продолжаем написание «прошивки». Ниже будут представлены фрагменты получившегося кода с комментариями.

Первым делом функцией #include подключаем библиотеку «mega8535.h», которая описывает архитектуру МК. И, перед тем как подключить библиотеку шины 1-wire, необходимо определить на каком порту, и на каком бите будет находиться датчик dallas. Затем подключаем библиотеку «stdio.h», необходимую для использования таких простых функций как putchar, getchar и т. д. Все это делаем в следующих строках, точнее сделал за нас генератор CodeVision:

  1. #include <mega8535.h>

  2. //1 Wire Bus functions

  3. #asm

  4. .equ __w1_port=0x18 ;PORTB

  5. .equ __w1_bit=4

  6. #endasm

  7. #include <1wire.h>

  8. #include <ds18b20.h>

  9. #include <delay.h>

  10. #include <stdio.h>

Аналогичным образом как определяли шину 1-wire, инициализируем LCD-дисплей на порт «С» микроконтроллера через ассемблеровскую вставку, после чего подключаем библиотеку «lcd.h»:

  1. //Алфавитно-цифровые функции LCD модуля

  2. #asm

  3. .equ __lcd_port=0x15 ;PORTC

  4. #endasm

  5. #include <lcd.h>

Далее идем программный код, который сгенерировал целиком CodeVisionAVR. Этот фрагмент кода относится к UART. Если кто хочет полностью разобраться в сгенерированном коде, у него есть такая возможность прочитать задание №5 на сайте: http://www.123avr.com. Лично я так и поступил.

  1. #define RXB8 1

  2. #define TXB8 0

  3. #define UPE 2

  4. #define OVR 3

  5. #define FE 4

  6. #define UDRE 5

  7. #define RXC 7

  8. #define FRAMING_ERROR (1<<FE)

  9. #define PARITY_ERROR (1<<UPE)

  10. #define DATA_OVERRUN (1<<OVR)

  11. #define DATA_REGISTER_EMPTY (1<<UDRE)

  12. #define RX_COMPLETE (1<<RXC)

  13. //Буфер приемника UART

  14. #define RX_BUFFER_SIZE 32

  15. char rx_buffer[RX_BUFFER_SIZE];

  16. #if RX_BUFFER_SIZE<256

  17. unsigned char rx_wr_index,rx_rd_index,rx_counter;

  18. #else

  19. unsigned int rx_wr_index,rx_rd_index,rx_counter;

  20. #endif

Для результата полученной выборки аналогово-цифрового преобразования определяем переменную «adc_data», а переменная «temp» для значений температуры окружающей среды.

  1. //флаг переполнения буфера приемника UART

  2. #bit rx_buffer_overflow;

  3. //двухбайтовая переменная для результата АЦП 

  4. unsigned char adc_data;

  5. //переменная для отправки температуры 

  6. int temp;

  7. // переменная частоты выборки АЦП (500Гц - по умолчанию)

  8. unsigned char TCNT0_value = 0x6;

Чтобы на LCD-дисплей можно было выводить русские символы, потребовалось определить массив и воспользоваться им в созданной функции «lcd_putsf_rus()», аргументом которой может быть русско-символьная строка.

  1. //массив во флэш-памяти для русских символов

  2. flash char Decode2Rus[255-192+1]= {

  3. 0x41,0xA0,0x42,0xA1,0xE0,0x45,0xA3,0xA4,

  4. 0xA5,0xA6,0x4B,0xA7,0x4D,0x48,0x4F,0xA8,

  5. 0x50,0x43,0x54,0xA9,0xAA,0x58,0xE1,0xAB,

  6. 0xAC,0xE2,0xAD,0xAE,0xAD,0xAF,0xB0,0xB1,

  7. 0x61,0xB2,0xB3,0xB4,0xE3,0x65,0xB6,0xB7,

  8. 0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0x6F,0xBE,

  9. 0x70,0x63,0xBF,0x79,0xE4,0x78,0xE5,0xC0,

  10. 0xC1,0xE6,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7};

  11. //функция вывода на LCD русско-символьной строки

  12. void lcd_putsf_rus(flash unsigned char *string)

  13. {

  14. char c;

  15. while (c=*string++)

  16. {

  17. if(c>=192) lcd_putchar(Decode2Rus[c-192]);

  18. else lcd_putchar(c);

  19. }

  20. }

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

  1. //печать на LCD "идет передача"

  2. void transfer()

  3. {

  4. lcd_clear();

  5. lcd_gotoxy(2,0);

  6. lcd_putsf_rus("идет");

  7. lcd_gotoxy(0,1);

  8. lcd_putsf_rus("передача");

  9. }

  10. //печать на LCD "ожидание команд"

  11. void expectation()

  12. {

  13. lcd_clear();

  14. lcd_gotoxy(0,0);

  15. lcd_putsf_rus("ожидание");

  16. lcd_gotoxy(1,1);

  17. lcd_putsf_rus("команд");

  18. }

  19. //Функция заставки при включении питания

  20. void expectation()

  21. {

  22. lcd_clear();

  23. lcd_gotoxy(1,0);

  24. lcd_putsf_rus("МОДУЛЬ");

  25. lcd_gotoxy(0,1);

  26. lcd_putsf_rus("АЦП-8бит");

  27. delay_ms(1500);

  28. lcd_clear();

  29. lcd_gotoxy(0,0);

  30. lcd_putsf("made by");

  31. lcd_gotoxy(1,1);

  32. lcd_putsf("GrigaN");

  33. delay_ms(1500);

  34. expectation();

  35. }

Значение температуры окружающей среды получаем по требованию с ПК. Определим для этого отдельную самостоятельную функцию get_send_temp(), которая поcле получения с датчика dallas значения температуры будет отправлять его посредством UART.

  1. //Функция чтения и отправки температуры

  2. void get_send_temp()

  3. {

  4. //распознавательный символ

  5. putchar(253);

  6. temp = 10*(ds18b20_temperature(0));

  7. putchar((char)(temp>>8));

  8. putchar((char)(temp));

  9. }

Далее я пропускаю кусок кода, отвечающий за обработку прерывания от приёмника UART.Читаем на странице сайта: http://www.123avr.com. задание №5.

Сердцем программы является ниже представленный листинг кода. Здесь в обработчике прерывания таймер сам себя реинициализирует из константы TCNT0_value и запускает одиночное аналого-цифровое преобразование.

  1. //Функция обработки прерывания от Таймера 0

  2. interrupt [TIM0_OVF] void timer0_ovf_isr(void)

  3. {

  4. //Реинициализация состояния Таймера 0

  5. //Получаем значение частоты из приемника UART

  6. TCNT0=TCNT0_value;

  7. //Запуск одиночного преобразования

  8. ADCSRA.6=1;

  9. }

После того как был получен результат преобразования, генерируется прерывание, в обработчике которого фильтруем полученное измерение и отправляем его по UART функцией putchar().

  1. //Функция обработки прерывания от АЦП

  2. interrupt [ADC_INT] void adc_isr(void)

  3. {

  4. //исключаем помехи АЦП

  5. if (ADCW<200)

  6. {

  7. adc_data=ADCW;

  8. putchar(254);

  9. putchar(adc_data);

  10. }

  11. }

Переходим к инициализации основных элементов МК. Особое внимание следует уделить инициализации UART и ADC. Если Вы помните из рисунка 6 CodeWizardAVR не позволил указать нужную скорость передачи в 500000 Bp. Правим регистр UBRR согласно таблице 13.10 в главе 13 источника [1].

  1. //Инициализация UART

  2. //Communication Parameters: 8 Data, 1 Stop, No Parity

  3. //USART Receiver: On

  4. //USART Transmitter: On

  5. //USART Mode: Asynchronous

  6. //USART Baud Rate: 500000

  7. UCSRA=0x00;

  8. UCSRB=0x98;

  9. UCSRC=0x86;

  10. UBRRH=0x00;

  11. UBRRL=0x00;

В инициализацию АЦП требуется добавить назначение регистра ADMUX, значением которого устанавливаются используемые «ноги» микроконтроллера непосредственно к которым подключается термопара. Также советую почитать задание №9 на сайте http://www.123avr.com. Автор доступным языком объяснил все тонкости.

  1. //Инициализация АЦП

  2. //ADC Clock frequency: 125,000 kHz

  3. //ADC Voltage Reference: Int., cap. on AREF

  4. //ADC High Speed Mode: Off

  5. //ADC Auto Trigger Source: None

  6. //порты: ADC1 - плюс, ADC0 - минус

  7. ADMUX=0xC9;

  8. //ИОН: Vref 2.56V внутренний/p>

  9. //выравнивание регистра ADCW, вправо

  10. //ADEN=0, АЦП запрешено;

  11. ADCSRA=0xE;

  12. SFIOR&=0xEF;

Переходим к главной функции main(). Согласно алгоритма представленного на рисунке 8, после инициализации выводим заставку на LCD-дисплей, то есть вызываем функцию prompt(). Затем микроконтроллер должен в бесконечном цикле проверять буфер приемника USART и при обнаружении в нём команды типа «символ» выполняется соответствующее действие. Смотрим листинг кода:

  1. void main(void)

  2. {

  3. //инициализация микроконтроллера

  4. init_avr();

  5. //глобальное прерывания разрешены

  6. #asm("sei")

  7. //вывод заставки

  8. prompt();

  9. //опрос буфера приёмника UART

  10. while (1)

  11. {

  12. switch (getchar())

  13. //инициализация модуля

  14. case 'i':

  15. putchar(252);

  16. //пускаем заставку

  17. expectation();

  18. break;

  19.  

  20. case 'p':

  21. //ADEN=1, АЦП разрещено

  22. ADCSRA=0x8E;

  23. //включаем таймер

  24. TCCR0=0x03;

  25. //пускаем заставку

  26. transfer();

  27. break;

  28.  

  29. case 's':

  30. //выключаем таймер

  31. TCCR0=0x00;

  32. //ADEN=0, АЦП запрещено

  33. ADCSRA=0xE;

  34. //пускаем заставку

  35. expectation();

  36. break;

  37.  

  38. case 'l':

  39. //выключаем таймер

  40. TCCR0=0x00;

  41. //ADEN=0, АЦП запрещено

  42. ADCSRA=0xE;

  43. //частота 500 Гц;

  44. TCNT0_value = 0x6;

  45. break;

  46.  

  47. case 'n':

  48. //выключаем таймер

  49. TCCR0=0x00;

  50. //ADEN=0, АЦП запрещено

  51. ADCSRA=0xE;

  52. //частота 1000 Гц

  53. TCNT0_value = 0x83;

  54. break;

  55.  

  56. case 'f':

  57. //выключаем таймер

  58. TCCR0=0x00;

  59. //ADEN=0, АЦП запрещено

  60. ADCSRA=0xE;

  61. //частота 2500 Гц;

  62. TCNT0_value = 0xCE;

  63. break;

  64.  

  65. case 't':

  66. if (ADCSRA==0x8E)

  67. {

  68. //выключаем таймер

  69. TCCR0=0x00;

  70. //ADEN=0, АЦП запрешено

  71. ADCSRA=0xE;

  72. //отправка температуры побайтно

  73. get_send_temp();

  74. //ADEN=1, АЦП разрешено

  75. ADCSRA=0x8E;

  76. //включаем таймер

  77. TCCR0=0x03;

  78. }

  79. else

  80. {

  81. //oтправка температуры побайтно

  82. get_send_temp();

  83. }

  84. break;

  85. }

  86. }

На этом все. Компилируем код, заливаем hex в микроконтроллер, предварительно выставив fuse-биты на тактирование от внешнего кварцевого резонатора на частоте 8 МГц.

Литература:

  1. Евстифеев А.В. Микроконтроллеры AVR семейства Mega. Руководство пользователя. – М.: Издательский дом «Додэка-XXI», 2007. – 592 c.: ил. (Серия «Программируемые системы»)

  2. Интернет ресурс: http://www.123avr.com

P.S. В следующей части рассмотрим написание управляющей и анализирующей программы для ПК, написанной в среде MS Visual Studio на языке С#.

Необходимо зарегистрироваться чтобы прочитать текст

Рейтинг:

Просмотров: 47698

Комментарии:

Нет комментариев.

Гости не имеют права добавлять комментарии и проставлять рейтинг.