АЦП ATmega16 - Страница 2 - Форум
Вторник, 27.08.2013, 22:06 Вы вошли как Гость | Группа "Гости"
Eugene's MCU
Главная | | Мой профиль | Выход | RSS

[ Личные сообщения() · Новые сообщения · Участники · Правила форума · Поиск · RSS ]

Страница 2 из 11«12341011»
Форум » Основной раздел » Разработка: программирование, схемотехника. » АЦП ATmega16 (Учебная программа - вольтметр на ATmega16)
АЦП ATmega16
eugenemcu

Дата: Суббота, 31.10.2009, 20:58 | Сообщение # 11

Группа: Администраторы
Сообщений: 115
Статус: Offline
Да, Сергей, отличная схема и на первый взгляд абсолютно работоспособная
Хочу обратить Ваше внимание на интересную особенность ЖКИ от Winstar - разные выводы питания для конструктивного исполнения A, B, C (вывод 1-GND, вывод 2-Udd) и исполнения D (наоборот), сравните два документа: WH1602C и WH1602D.
Встречный вопрос: в CodeVision есть библиотека под ЖКИ или Вы планируете писать драйвер самостоятельно? Если не найдёте под CVAVR, то как вариант можете применить мой http://eugenemcu.ru/publ/1-1-0-15 он для ЖК 16X1, но изменения там в одну команду, адаптировать его под КодВижн тоже дело техники.
Кстати вспомнил, делал тахометр и терморегулятор для ВАЗ2106 на Mega16 и WH1602D, только здесь он низкотемпературный, питание двухполярное. Вот схемка, может кому пригодится


8237515.gif(62Kb)

[ (RU) ]

us4ilq

Дата: Понедельник, 02.11.2009, 19:06 | Сообщение # 12

Группа: Пользователи
Сообщений: 48
Статус: Offline
eugenemcu
Спасибо за ответ!
ЖКИ от Winstar у меня с буквой А, о разнице в распиновке я знаю.
Правда рисовал по памяти, может что и перепутал
В CodeVision есть библиотека под ЖКИ, и при чем можно выбрать любой порт, а он сам предлагает схему подключения.
Вот этим я и хочу воспользоваться, поскольку писать самостоятельно еще и драйвер я просто не одолею этого.
На днях (может даже и завтра) , генератором начального кода сгенерирую этот самый начальныц код и выложу сюда.
Да! к стати. Товарищ сегодня привез TL431 6 штучек в корпусе ТО92, кажется так он называется, так что буду экспериментировать.

Добавлено (02.11.2009, 13:44)
---------------------------------------------
Здравствуйте!
Вот то что обещал в прошлом сообщении.
Тоесть то что мне выдал генератор начального кода CVAVR, незнаю все ли установки я сделал правильно.
Руководствовался я вот этим:
http://avr123.nm.ru/z09.htm и http://avr123.nm.ru/z09b.htm, а также читал и другие обучающие курсы.

Code
/*****************************************************
This program was produced by the
CodeWizardAVR V2.03.9 Evaluation
Automatic Program Generator
© Copyright 1998-2008 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : VOLTMETR.1
Version : 1.0
Date    : 02.11.2009
Author  : Freeware, for evaluation and non-commercial use only
Company : US4ILQ
Comments:     
Вольтметр постоянного тока, с верхним пределом 5 вольт,
Вывод результата измерения на ЖКИ 1602 от ВИНСТАР.

Chip type               : ATmega16
Program type            : Application
AVR Core Clock frequency: 8,000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 256
*****************************************************/

#include <mega16.h>

// Alphanumeric LCD Module functions
#asm
       .equ __lcd_port=0x15 ;PORTC
#endasm
#include <lcd.h>

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Reinitialize Timer 0 value
TCNT0=0x83;
// Place your code here

}

#include <delay.h>

#define ADC_VREF_TYPE 0x00

// ADC interrupt service routine
interrupt [ADC_INT] void adc_isr(void)
{
unsigned int adc_data;
// Read the AD conversion result
adc_data=ADCW;
// Place your code here

}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

PORTA=0x00;
DDRA=0x00;

PORTB=0x00;
DDRB=0x00;

PORTC=0x00;
DDRC=0x00;

PORTD=0x00;
DDRD=0x00;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125,000 kHz
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x03;
TCNT0=0x83;
OCR0=0x00;

TCCR1A=0x00;
TCCR1B=0x00;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;

MCUCR=0x00;
MCUCSR=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;

ACSR=0x80;
SFIOR=0x00;

// ADC initialization
// ADC Clock frequency: 125,000 kHz
// ADC Voltage Reference: AREF pin
// ADC Auto Trigger Source: None
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x8E;

// LCD module initialization
lcd_init(16);

// Global enable interrupts
#asm("sei")

while (1)
          {
          // Place your code here

          };
}

к сожалению пришлось удалить большинство коментариев, т.к. сообщение непомещалось.

Теперь как я полагаю нужно изменить эту строку:
#define ADC_VREF_TYPE 0x00
на
#define ADC_VREF_TYPE 0x02

Чтобы указать на какой вывод будет подаваться измеряемое напряжение,
и что усиление неиспользовано, а результат АЦП в регистрах ADCH и ADCL будет выровнен вправо. А что же делать дальше???


[ (UA) ]

eugenemcu

Дата: Понедельник, 02.11.2009, 19:32 | Сообщение # 13

Группа: Администраторы
Сообщений: 115
Статус: Offline
Здравствуйте, Сергей
Мне сложно оценить уровень вашей подготовкии и подобрать нужный стиль общения. Попробуем на самом простом языке.

по идее:
Вы собираетесь измерять значение постоянного тока, поэтому вам нет необходимости запускать 1000 измерений в секунду, как это сделано в приведённом выше примере. Для целей отладки достаточно делать это хотя бы один раз в полсекунды. Для этого применим прерывания по переполнению от 16-разрядного таймера T1 с которых и будет начинаться процесс измерения и отображения результата на LCD.
по технике:
использованный в вашем коде таймер T0, на 8 МГц не даст такого большого интервала времени (даже при максимальном коффициенте предделителя равном 1024) из-за его малой разрядности - он может считать только до 256.
Расчитать нужное число тактов таймера T1 для выбранного интервала времени можно на странице ATmega Таймеры T1, T3.
Для 500 мс при частоте 8МГц и коэффициенте предделителя равном 256 это будет число 0x6109, которое необходимо вычесть из значения пререполнения счётчика 0xFFFF. Тогда инициализационный код таймера:

Code

                TCCR1B|=(1<<CS12); // Предделитель для T1 = 256.
                TCNT1H=(0xFF-0x61); // Старший байт счётчика.
                TCNT1L=(0xFF-0x09); // Младший байт счётчика.
                TIMSK|=(1<<TOIE1); // Разрешить прерывание по переполнению Т1.

Этот код заставит T1 переполняться каждые полсекунды, и выходить на соответствующий обработчик, остаётся только объявить его следующим образом:

Code

interrupt [TIM1_OVF] void timer1_ovf_isr(void) // Подпрограмма обработки прерывания по переполнению T1
{
TCNT1H=0xFF-0x61; TCNT1L=0xFF-0x9; // Переинициализация счётчика на 500мс.
PORTA^=(1<<LED); Изменить состояние светодиода. Отладка.
}

Обратите внимание на строку PORTA^=(1<<LED); я предлагаю временно использовать для отладки светодиод. Припаяйте его анодом к питанию и с катода через резистор 470 Ом например на PORTA.0, прописав в программе:

Code

#define LED 0 // Вывод светодиода.
...         
DDRA|=(1<<LED); // Вывод светодиода на выход.
PORTA|=(1<<LED); // Погасить светодиод


При нормальной работе таймера он должен загораться и гаснуть 2 раза в секунду.



[ (RU) ]

us4ilq

Дата: Вторник, 03.11.2009, 18:14 | Сообщение # 14

Группа: Пользователи
Сообщений: 48
Статус: Offline
Спасибо за ответ и Ваше терпение ко мне.
Уровень моей подготовки смело можно принять за НОЛЬ.
Вот из последнего Вашего сообщения стало немного по понятней
Однако я совсем нехочу просто копировать Ваш или чей то еще код, а посему буду теперь разбираться
в том что Вы мне посоветовали.

Еще раз
ОГРОМНОЕ СПАСИБО!


[ (UA) ]

eugenemcu

Дата: Вторник, 03.11.2009, 19:30 | Сообщение # 15

Группа: Администраторы
Сообщений: 115
Статус: Offline
Чтобы долго не топтаться на месте подкину ещё пищи для размышлений.
Для управления процессом измерений введём переменную Status, начальное состояние признака после подачи питания Status=0. А так же переменную для хранения выходного кода АЦП - AdcCode.

Существует правило - не загружать обработчики прерываний тем,что может быть нормально обработано в фоне, то есть в бесконечном цикле while(1) функции main. Хотя в обработчике прерывания по переполнению T1 нам нужно просто запустить АЦП на преобразование, для сохранения общего стиля, ограничимся установкой признака начала измерения - Status=1:

Code

interrupt [TIM1_OVF] void timer1_ovf_isr(void) // Подпрограмма обработки прерывания по переполнению T1         
{         
           TCNT1H=0xFF-0x61; TCNT1L=0xFF-0x9; // Переинициализация счётчика на 500мс.         
           PORTA^=(1<<LED); //Изменять состояние светодиода. Отладка
           Status=1; // запустить преобразование АЦП.
}

а в фоне, который крутится бесконечно и достаточно быстро, отловив значение Status=1, начнём преобразование АЦП:
Code

if (Status==1) // Если необходимо запустить АЦП...
{
           ADCSRA|=(1<<ADSC); // Начать измерение.
           Status=2; // Ждать завершения преобразования.
}

Через несколько сотен тактов АЦП завершит измерение и вызовется, объявленный нами ранее обработчик по завершению преобразования АЦП, в котором можно установить соответствующий статус и скопировать результат преобразования в переменную AdcCode:
Code

interrupt [ADC_INT] void adc_isr(void) // Обработчик по завершению преобразования АЦП
{         
           Status=3; // Преобразование завершено.
           AdcCode=ADCW; // Скопировать выходной код АЦП.
}

и опять же в фоне можно приступить к отображению полученного значения на ЖКИ:
Code

if (Status==3) // Если преобразование завершено...
{
           AdcCode=(AdcCode>>2); // Убрать два младших разряда результата
           // ЗДЕСЬ МОЖНО ОТОБРАЗИТЬ РЕЗУЛЬТАТ НА ЖКИ.
           Status=0; // Вернуть признак в исходное состояние, ждать следующего срабатывания таймера
}



[ (RU) ]

eugenemcu

Дата: Вторник, 03.11.2009, 19:35 | Сообщение # 16

Группа: Администраторы
Сообщений: 115
Статус: Offline
в предыдущий пост не влез исходник программы на вашем любимом CVAVR:
Code

#include <mega16.h>        
// Alphanumeric LCD Module functions        
#asm        
.equ __lcd_port=0x15 ;PORTC        
#endasm        
#include <lcd.h>        
#include <delay.h>        
#define ADC_VREF_TYPE 0x02 // Канал АЦП.      
#define LED 0 // Вывод светодиода.        

unsigned char Status=0; // Управляющий признак.
unsigned int AdcCode; // Для хранения и обработки результата измерения.

void main(void)        
{        
           DDRA|=(1<<LED); // Вывод светодиода на выход.        
           PORTA|=(1<<LED); // Погасить светодиод

           TCCR1B|=(1<<CS12); // Предделитель для T1 = 256. Начать счёт.       
           TCNT1H=(0xFF-0x61); // Старший байт счётчика.  Инициализация на 0,5 сек.      
           TCNT1L=(0xFF-0x09); // Младший байт счётчика.        
           TIMSK|=(1<<TOIE1); // Разрешить прерывание по переполнению Т1.

           ACSR=0x80;        
           SFIOR=0x00;        
           ADMUX=ADC_VREF_TYPE & 0xff; // Выбрать канал АЦП.                
           ADCSRA=0x8E; // Частота работы АЦП - 125000 kHz, внешний ИОН на выводе AREF,  режим однократного запуска измерений .       
           lcd_init(16); // Инициализация LCD.       
           #asm("sei") // Разрешить прерывания в программе.

           while (1)        
           {        
               if (Status==1) // Если необходимо запусить АЦП...
               {
                    ADCSRA|=(1<<ADSC); // Начать измерение.
                   Status=2; // Ждать завершения преобразования.
               }
               if (Status==3) // Если АЦП завершил преобразование...
               {
                   AdcCode=(AdcCode>>2); // Убрать два младших разряда из результата.
                   // ЗДЕСЬ МОЖНО ОТОБРАЗИТЬ РЕЗУЛЬТАТ НА ЖКИ.        
                   Status=0; // Исходное состояние управляющей переменной, ждать следующего срабатывания таймера.
               }
           }
               
}

interrupt [TIM1_OVF] void timer1_ovf_isr(void) // Подпрограмма обработки прерывания по переполнению T1        
{        
TCNT1H=0xFF-0x61; TCNT1L=0xFF-0x9; // Переинициализация счётчика на 500 мс.        
PORTA^=(1<<LED); //Измениять состояние светодиода. Отладка
Status=1;  // Начать измерение.      
}
interrupt [ADC_INT] void adc_isr(void) // Обработчик по завершению преобразования АЦП
{        
          AdcCode=ADCW; // Скопировать выходной код АЦП.
          Status=3; // Преобразование завершено.
}        

Скажу по секрету: проверил программу, отсылая переменную AdcCode в COM-порт ПК. Всё работает нормально на втором канале АЦП
Вам остаётся только отобразить значение на ЖК, используя функции из lcd.h, для начала ,наверное, просто в виде кода АЦП. Нужно только выделить разряды сотен, десятков и единиц в переменной AdcCode, я подозреваю, что драйвер этого делать не умеет.



[ (RU) ]

us4ilq

Дата: Среда, 04.11.2009, 16:17 | Сообщение # 17

Группа: Пользователи
Сообщений: 48
Статус: Offline
Пробовал Ваши рекомендации компилятор "ругается " на вот эти две строки, наверное что то с синтаксисом не так:

TCCR1B|=(1<<CS12); // Предделитель для T1 = 256
TIMSK|=(1<<TOIE1); // Разрешить прерывание по переполнению Т1.

А именно в сообщении об ошибке указывает на CS12 и TOIE1.

Схему выкладываю снова, немного подправил (обозначил выводы LCD).

Начал было разбираться с 16разрядными таймерами Просто кошмар, столько всего понаписано! еще больше запутался Кстати разбираюсь по описанию (на русском языке) Мега 128 на сайте http://www.gaw.ru. У меня есть печатная версия, если интересует, то могу выслать Вам , можно будет
выложить для всеобщего пользования.

А что до способа вывода на LCD то я думал использовать sprintf, в CVAVR она находится в файле stdio.h. У меня есть маленькая статейка по этому поводу, однако с ней тоже еще надоразобраться.

Добавлено (04.11.2009, 14:38)
---------------------------------------------
Евгений!
У меня тут возникла целая куча глупых вопросов, с Вашего позволения я их начну задавать... ну хотябы вот это - а почему нельзя
TCCR1B|=(1<<CS12); // Предделитель для T1 = 256
записать както вот так к примеру
TCCR1B=0xXX?
Ну согласитесь, так было бы гораздо более читабельно. Или в данном случае такая запись недопустима?

Добавлено (04.11.2009, 15:20)
---------------------------------------------
И еще вопрос не менее глупый: а зачем нам вообще нужен таймер для такой простой програмки? Ведь она всего лиш учебная. Я спрашиваю об этом потому, что где то (не помню где именно) встречал подобные программы без применения таймеров.

А вот это Status переменная? Если да - то я ее должен обьявить? Тогда какой тип данных она должна хранить? И еще , что то я совсем отупел, откуда берутся ее параметры =1; =2; =3 ?
8938021.jpg(111Kb)

[ (UA) ]

eugenemcu

Дата: Среда, 04.11.2009, 17:42 | Сообщение # 18

Группа: Администраторы
Сообщений: 115
Статус: Offline
Здравствуйте, Сергей. Отвечаю на ваши вопросы:
1. Компилятор ругается на CS12 и TOIE1.
CS12 и TOIE1 - это стандартные имена битов в регистрах TCCR1B и TIMSK. Компилятор по ходу текста заменяет эти названия на их порядковые номера в регистре, руководствуясь строками заголовочных файлов mega16.h и(или) mega16_bits.h:
Code

        #define  CS12  2 // Prescaler source of Timer/Counter 1
        #define  TOIE1 2 // Timer/Counter1 Overflow Interrupt Enable
                        

в итоге получается:
Code

        TCCR1B|=(1<<2);
        TIMSK|=(1<<2);
                        

У меня установлен CVAVR v2.04.4a, вероятно в этой версии введены другие имена битов. Откройте указанные заголовочные файлы в директории C:\cvavreval\inc (возможно он там у вас вообще один) и уточните имена битов в регистрах TCCR1B и TIMSK.

2. Зачем писать TCCR1B|=(1<<CS12); вместо TCCR1B =0x04?
Можно писать и TCCR1B =0x04, но только, если вам не дорого состояние остальных битов в этом регистре, потому что такая запись сбрасывает их в ноль. Вы могли установить один из них в предыдущих командах, а в этой, сами того не заметив, сбросите. Первая запись использует операцию побитового логического “ИЛИ” и за счёт этого оставляет состояние остальных битов регистра неизменными (см. статью Операции с переменными и регистрами). Можно использовать и простое присвоение, но при этом всегда смотреть, не сбрасываете ли вы нужные биты, и это будет даже на пару тактов быстрее. На счёт читабельности не уверен, что из записи ADCSRA=0x8E легко понять какие именно биты здесь устанавливаются.

3. Зачем нам вообще нужен таймер для такой простой програмки?
На самые простые вопросы сложнее всего отвечать. Альтернатива задержки на таймере только одна – циклическая операция, например отнимания от огромного числа единицы в течение нужного времени. Использовать её значит гробить быстродействие фона программы, ведь пока она не пройдёт такую задержку не сможет делать ничего полезного разве что в прерываниях, а это очень важно для насыщенной программы.
Вообще говоря, для меня универсальный вариант организации задержек такой – запускаем таймер, вызывающий прерывания каждые 10 миллисекунд. Далее, если мы хотим организовать задержку в 100 мс, то записываем в некую переменную число 10 – Tmr=10; (это начало задержки) и в обработчике, каждые 10мс, отнимаем от него единицу – Tmr- -; пока она не станет равной нулю (это конец задержки). Если нужно реализовать ещё один интервал, например, в секунду используем ещё одну переменную Tmr2=100; и в обработчике делаем то же самое Tmr2- -; пока Tmr2 не равно нулю. Так, используя всего один таймер, можно реализовать любое количество задержек. Рекомендую сразу привыкать к таким решениям, а про задержки в виде пустых циклов забыть

4. Status – это переменная? Я ее должен объявить? Какой тип данных она должна хранить?
Status введён для управления последовательностью действий программы это просто признак текущего состояния; объявлен в приведённом мной исходнике, как переменная типа unsigned char (значения от 0 до 255).
Можете обозвать его так, как вам будет угодно. Если вы внимательно посмотрите на фон программы, то увидите, что там постоянно отслеживается текущее значение признака Status и выполняются необходимые действия.
Status=1; так мы даём понять фону, что сработал таймер и пора запускать АЦП на преобразование.
Status=3; указывает на то, что преобразование закончилось, результат скопирован в переменную AdcCode и можно приступать его обработке и отображению.
Status=2; позволяет больше не проходить по ветке соответствующей значению Status=1 иначе команда ADCSRA|=(1<<ADSC); будет выполняться многократно.
Status=0; также защитное значение - позволяет избежать повторных проходов по ветке обработки и отображения результата на ЖКИ.

P.S. В качестве полезного чтива по технической части очень рекомендую книгу "Микроконтроллры AVR семейств Tiny и Mega фирмы "ATMEL". Евстифеев А. В." Это фактически перевод DataSheet с хорошими пояснениями. Имея её, вы вряд ли будете нуждаться в чём-то ещё


[ (RU) ]

us4ilq

Дата: Суббота, 07.11.2009, 20:24 | Сообщение # 19

Группа: Пользователи
Сообщений: 48
Статус: Offline
Разобрался с ошибкой компилятора вот по этому поводу
TCCR1B|=(1<<2);
TIMSK|=(1<<2);
вспомнил что AVR123nm.ru советовал добавить библиотеку его изобретения: #include <m8_128.h>
для работы с битами. Теперь я ее добавил и компилятор не возмущается.
От же, одну проблему победил.

Добавлено (07.11.2009, 17:55)
---------------------------------------------
Здравствуйте Евгений!
Пытался я осилить вывод информации на ЖКИ с помощью sprintf
Вроде все по описаниям делал , вот только ничего невыходит.
Ниже даю код пробной программки написаной мною для пробы.

Code

#include <mega16.h>
#include <stdio.h>

// Alphanumeric LCD Module functions
#asm
     .equ __lcd_port=0x15 ;PORTC
#endasm

#include <lcd.h>

// Declare your global variables here

unsigned int AdcCode;   //  Для хранения и обработки результата измерения.
unsigned char lcd_buffer[33];   //  Буфер LCD-дисплея

void main(void)
{

   lcd_init(16);
   AdcCode=0x1000010011000010;
   while (1)
       {
                        // ОТОБРАЖЕНИЕ НА ЖКИ.

              lcd_clear();
               
              lcd_gotoxy(0,0);
              sprintf(lcd_buffer,"\tVOLTMETR\nU=%i.%uvolt",AdcCode/100,AdcCode0);
    //delay_ms(1000000);
              //while (1);

         };
}

В первой строке ЖКИ должно появляться: VOLTMETR
Во второй строке должно появляться: U=XX.XXvolt
ХХ.ХХ - какието цифры.

На индикаторе вообще ничего нет.

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

Добавлено (07.11.2009, 20:00)
---------------------------------------------
И всетаки я ее ПОБЕДИЛ!!!

Добавил
lcd_puts(lcd_buffer);
сразу после
sprintf(lcd_buffer," VOLTMETR\nU=%i.%uvolt",AdcCode/100,AdcCode0);

Теперь попробую все это в самом вольтметре.

Добавлено (07.11.2009, 20:24)
---------------------------------------------
А вот в вольтметре работать нехочет.
По прежнему чистый дисплей


[ (UA) ]

us4ilq

Дата: Суббота, 07.11.2009, 21:23 | Сообщение # 20

Группа: Пользователи
Сообщений: 48
Статус: Offline
Просто нужно было какое нибудь число вывести во второй строке ЖКИ... типа это результат
Код счас попробую прицепить
Code

#include <mega16.h>
#include <m8_128.h>
#include <delay.h>
#include <stdio.h>
#asm
      .equ __lcd_port=0x15 ;PORTC
#endasm
#include <lcd.h>
#define ADC_VREF_TYPE 0x02     
#define LED 0           
unsigned char Status=0;      
unsigned int AdcCode;      
unsigned char lcd_buffer[33];    

                      // Подпрограмма обработки прерывания по переполнению T1
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
       TCNT1H=0xFF-0x61; TCNT1L=0xFF-0x9;     
       PORTA^=(1<<LED);              
       Status=1;         
}

                      // Подпрограмма обработки прерывания    
                      //по завершению преобразования АЦП
interrupt [ADC_INT] void adc_isr(void)
{
       AdcCode=ADCW;     
       Status=3;      
}

void main(void)
{
TCCR1A=0x00;
TCCR1B|=(1<<CS12);        
TCNT1H=0xFF-0x61;         
TCNT1L=(0xFF-0x09);       
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

MCUCR=0x00;
MCUCSR=0x00;

TIMSK|=(1<<TOIE1);         

ACSR=0x80;
SFIOR=0x00;

ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x8E;

DDRA|=(1<<LED);     
PORTA|=(1<<LED);     

TCCR1B|=(1<<CS12);     
TCNT1H=(0xFF-0x61);     
TCNT1L=(0xFF-0x09);         
TIMSK|=(1<<TOIE1);      

ADMUX=ADC_VREF_TYPE & 0xff;    
ADCSRA=0x8E;     
lcd_init(16);        
#asm("sei")         
while (1)
         {
          if (Status==1)      
           {
           ADCSRA|=(1<<ADSC);      
           Status=2;            
           }
                 if (Status==3)     
                 {
                 AdcCode=(AdcCode>>2);     

                      // ОТОБРАЖЕНИЕ НА ЖКИ.
                 lcd_gotoxy(0,0);
                 sprintf(lcd_buffer,"  VOLTMETR\nU=%i.%uvolt",AdcCode/100,AdcCode0);
                 lcd_puts(lcd_buffer);
                 delay_ms(1000);
                 //while (1);
                 Status=0;         
                 }
         };
}



[ (UA) ]

Форум » Основной раздел » Разработка: программирование, схемотехника. » АЦП ATmega16 (Учебная программа - вольтметр на ATmega16)
Страница 2 из 11«12341011»
Поиск: