У каждого в жизни был момент, когда понимаешь, «Надо покупать осциллограф!». В моей практике,в большинстве случаев осциллограф нужен был для наблюдения за формой сигнала (или вообще показывал его наличие), тогда как основные измерения и исследования проводились на других приборах. Многие сейчас со мной поспорят, ну что поделаешь мне так удобней.Поэтому я решил сделать простой осциллограф-пробник. Он не будет отличаться хорошими характеристиками, главная цель, как можно популярней объяснить принцип работы!В конце статьи можно найти архив со всеми исходниками и материалами, которые потребуются. Итак начнем...
Цифровой сигнал - это массив чисел(если сразу по простому), каждое число это значение напряжения в данное время. Отсчеты делаются с определенной частотой, что и называется частотой дискретизации. Переводом из аналогового сигнала в дискретный и занимается АЦП. Существуют специальные микросхемы реализующие данную функцию, но микроконтроллеры специально снабжаются выводами с которых можно снимать значения. Откроем datasheet на Atmega8, там видим фразу: 8 каналов(или 6 для корпуса PDIP) 10-бит АЦП. Т.е. можно подвести 8 сигналов к каждому из этих каналов, и снимать с каждого свой сигнал! 10-бит же означает, что в каждый момент времени напряжение кодируется 2-чным числом из 10 цифр. Запомните этот факт.
Теперь, наш АЦП не понимает отрицательного напряжения, он производит измерения от 0-GND до AREF. Верхний порог может быть задан в регистре ADMUX как внутренний источник = 2,56 В или же может быть равен напряжению на ножке AVCC(что обычно и делается). Так же в ADLAR(смотри рисунок ниже) можно задавать порядок заполнения результата.
Адрес MUX 0x0000 соответствует входу ADC0, и по аналогии продолжается (если не поняли смотрите в даташите стр 199).
Теперь, запуск АЦП. АЦП может работать в 2 режимах. Первый - однократный режим (Single Conversation), в данном режиме мы подаем команду "Измерить!" он измеряет и выключается (но это так образно). Второй - постоянный запуск (Free Running), где мы настраиваем все, включаем и он работает а мы постоянно снимаем значения. Для реализации нашей задачи больше подходит второй режим, но так сложней контролировать измерение, поэтому будем использовать первый.
Настройка режима АЦП происходит в регистре ADCSRA.
Последнее, что осталось, регистры результатов ADCH - старший бит ADCL - младший. Про них рассказывать не буду, на картинке все видно и понятно.
С теорией все! Теперь напишем программку! Для отладки и обучения АЦП соберем схему в Proteus. Будем делать следующее:
-измерять уровень на входе;
-выводить уровень в двоичном коде (с помощью 8 светодиодов).
Для этого будем работать в режиме ADLAR=1 и считывать только старшие биты ADCH (т.е. 2 младших бита мы теряем, теряется точность, но в допустимых для меня пределах). Программа написана в AVR Studio.
int main(void) { DDRD=0xFF; ADMUX = 0b01100000;//Настроили верхний порог на напряжение AVCC подвели 3,3В //ADLAR=1 и снимаем АЦП с ножки ADC0 ADCSRA = 0b10001101; //Настраиваем режим АЦП, включаем Single Mode, снимаем АЦП с входа ADC0 _delay_us(10); while(1) { ADCSRA |= 0x40;//Включаем АЦП while((ADCSRA & 0x10)==0);//ждем завершения PORTD=ADCH;//выводим результат } }
Прошиваем смотрим что получилось. Когда синус увеличивается от 0 до 3.3, мы видим как значение растет до максимума, но когда синус уходит в отрицательную часть у нас стабильно 0.
Для решения этой проблемы нам надо поднять наш сигнал на 1.6 В (половина всего диапазона), т.е. надо прибавить к сигналу половину питания, а сам сигнал в 2 раза ослабить, чтобы значение на входе не превышало наши рамки 0-3.3 В. НО! Так как статья учебная, и тут главное все вам объяснить пойдем проще! Для проверки работы нашего устройства мы будем использовать выход со звуковой карты (а на ПК запущен генератор сигналов), поэтому мы просто кидаем резистор 470 Ом между +3 В и входом АЦП. Так мы получим желаемое смещение.
В итоге, мы сигнал оцифровали. Осталось вывести его на экран.
Для своего проекта я выбрал экран от nokia1100, почему? Да потому что только его нашел в своем городе + на него есть макет в Proteus. Можно использовать и другие, главное данные у нас уже есть (научились их получать!).
Описывать как инициализировать экран я не буду (в интернете и так много доступной информации, не хочу повторяться + я расставил как можно больше комментариев в исходниках), а просто приведу текст программы с комментариями:
#include "nokia1100.h" // Подключаем библиотеку NOKIA1100 unsigned int n[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; unsigned int deltaU=4,deltaT=0; unsigned int buffer[96]; int flag=0; void LCD_Signal(int index,int znachenie,int deltaU){//функция вывода пикселя в столбце znachenie=znachenie/deltaU; unsigned int h; for(unsigned int i=0;i<8;i++){ nlcd_GotoXY(index,7-i); h=1; for(unsigned int j=0;j<8;j++){ if(i*8+j==znachenie){h=0; nlcd_SendByte(DATA_LCD_MODE,n[j]);} } if(h) nlcd_SendByte(DATA_LCD_MODE,0x00); } } void function_buttons(){//обработка кнопок while(PINB==0x01) flag=1; while(PINB==0x02) flag=2; if(flag==1)deltaU+=2; if(flag==2) deltaT+=10; } int main(void) { nlcd_Init();//инициализация дисплея _delay_us(10); ADMUX =0b01100000;//Настроили АЦП от 0 до AVCC на который мы подаем 3,3 В ADCSRA = 0b10001100;//Настраиваем режим АЦП, вход настраиваем так же на ADC0 while(1) { DDRB=0x00; PORTB=0x00; for(int i=0;i<96;i++){ ADCSRA |= 0x40;//Включаем АЦП while((ADCSRA & 0x10)==0);//Ждем завершения buffer[i]=ADCH;//Записываем в буфер _delay_us(deltaT);//задержка для уменьшения частоты дискритизации } for(int i=0;i<96;i++){//Выводим буфер на экран function_buttons(); LCD_Signal(i,buffer[i],deltaU); } } }
Подключаемые файлы находятся в архиве к статье!
Теперь собираем новую (или переделываем старую) схему для протеуса.
Вы можете явно наблюдать за тем что у нас получилось! Сигнал (пускай и не сверх быстро), но выводится на экран. Пора собирать устройство в железе! Делать плату я не стал, собрал все на макетке, главное, увидеть как все то что вы сейчас прочитали (а может даже написали сами) заработает!
Питание дисплея от 1100 +3В, я поставил по стандартной схеме 1235 Б (стабилизатор 3В их много аналогов, например LM7803), снабдив его двумя конденсаторами. На яркость подал через резистор (ограничение по току).
Прошиваем контроллер, фьюзы? Выставляются только тактовая частота, и от этого зависит скорость отображения и собственно возможности АЦП. Еще устанавливаем уровень BODLEVEL=1.
Надеюсь статья будет полезна и АЦП теперь не вызовет не у кого вопросов и проблем, но если вызовет задавайте их в коментариях
Прикрепленные файлы:
- Материалы для статьи.rar (4886 Кб)
Комментарии (25) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
[Автор]
[Автор]
[Автор]
[Автор]
[Автор]
[Автор]
[Автор]
nlcd_SendByte(CMD_LCD_MODE,0x22); nlcd_SendByte(CMD_LCD_MODE,0x95);
Вот со значениями отправляемыми поиграйтесь, попробуйте число увеличить. Если не работает, то тогда дело либо в питании, померьте вольтметров должно быть 3В. Либо же вам попался плохой экран, что самое печальное.
[Автор]
[Автор]