Фотодатчик на Tiny13

Обсуждаем контроллеры компании Atmel.
seagull72
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вт май 04, 2010 20:05:38

Фотодатчик на Tiny13

Сообщение seagull72 »

Доброго времени суток.

Это моя первая попытка разобраться в микроконтроллерах, так что прошу сильно не пинать, а, наоборот, помочь по возможности.

Итак. Attiny13. Фотодатчик. Алгоритм такой - АЦП снимает напряжение и сравнивает его с двумя пороговыми (заданными в программе). Если напряжение превысит верхний пороговый уровень, то на выходе МК - лог. 1, если напряжение снизится ниже нижнего порогового уровня, то МК ждет 30 сек и еще раз проводит измерение напряжения, если оно и после этого ниже нижнего уровня - то на выходе лог. 0.

Программу писал в Atmel Studio 7, на С. Компилятор ошибок не показал. Загнал программу в Proteus - на выходе постоянно лог. 1.

Сам, ессно, буду разбираться и искать, но если кто подскажет - буду очень признателен. И еще, подскажите, что можно почитать про C для МК AVR. Есть Прокопенко и Белов.

Текст программы:

/*
* project photocell.c
*
* Created: 06.12.2015 15:30:58
* Author : seagull
*/

#include <avr/io.h>
#include <avr/iotn13.h>
#include <util/delay.h>


int main(void)
{

// Конфигурирование порта B PORT4 (нога 3) на выход
DDRB=(0<<DDB5) | (1<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
PORTB=(0<<PORTB5) | (1<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

// Отключение компаратора
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIS1) | (0<<ACIS0);

// Отключение таймера
TCCR0A=(0<<COM0A1) | (0<<COM0A0) | (0<<COM0B1) | (0<<COM0B0) | (0<<WGM01) | (0<<WGM00);
TCCR0B=(0<<WGM02) | (0<<CS02) | (0<<CS01) | (0<<CS00);
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Запрет прерываний
GIMSK=(0<<INT0) | (0<<PCIE);
MCUCR=(0<<ISC01) | (0<<ISC00);
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);

// Конфигурирование АЦП
ADCSRA=(1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
ADMUX=(1<<REFS0) | (1<<ADLAR) |(0<<MUX0)| (0<<MUX1); // Смещение результата влево, Аналоговый сигнал на PB5

unsigned int pcon; // Порог включения
unsigned int pcoff; // Порог выключения
unsigned int tdelay; // Время задержки
char temp; // Стартовое положение
unsigned int vv; // Измереное напряжение
char v_temp;
unsigned int v;

pcon=4.9/5*1024; // Задать порог включения
pcoff=4.4/5*1024; // Задать порог выключения
tdelay=30000; // Задать время задержки
temp=1; // Датчик включен
v_temp=1;

_delay_us(50);

while (1)
{
ADCSRA|=(1<<ADSC); //Начать преобразование
while (!(ADCSRA & (1<<5)));
// loop_until_bit_is_set(ADIF); // while ((ADCSRA&_BV(ADIF))==0x00); //Дождаться окончания преобразования
v=ADCH;
ADCSRA|=(0<<ADSC);
ADCSRA|=(0<<ADIF);;
if (vv>=pcon)
{
temp=1;
v_temp=1;
goto link;
}
if (vv<=pcoff && temp==1)
{
temp=0;
_delay_ms(tdelay);
goto link;
}
if (vv<=pcoff && temp==0)
{v_temp=0;
goto link;
}
link:
PORTB|=(v_temp<<PORTB4);
}
}

И сама программа:
Вложения
main.c
(2.07 КБ) 388 скачиваний
Живём как положено. Положено на всё.
Аватара пользователя
GRAF
Мудрый кот
Сообщения: 1867
Зарегистрирован: Ср янв 23, 2008 22:11:54
Откуда: Калининград

Re: Фотодатчик на Tiny13

Сообщение GRAF »

Проверяйте, я уже спать хочу.

Код: Выделить всё

/*
 * project photocell.c
 *
 * Created: 06.12.2015 15:30:58
 * Author : seagull
 */

#include <avr/io.h>
#include <avr/iotn13.h>
#include <util/delay.h>


int main(void)
{

// Конфигурирование порта B PORT4 (нога 3) на выход
DDRB=(0<<DDB5) | (1<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
PORTB=(0<<PORTB5) | (1<<PORTB4) | (0<<PORTB3) | (0<<PORTB2) | (0<<PORTB1) | (0<<PORTB0);

// Отключение компаратора
ACSR=(1<<ACD);


// Запрет прерываний
GIMSK=(0<<INT0) | (0<<PCIE);
MCUCR=(0<<ISC01) | (0<<ISC00);
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (0<<TOIE0);

// Конфигурирование АЦП
ADCSRA=(1<<ADEN) | (0<<ADSC) | (0<<ADATE) | (0<<ADIF) | (0<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (0<<ADPS0);
ADCSRB=(0<<ADTS2) | (0<<ADTS1) | (0<<ADTS0);
ADMUX=(1<<REFS0) | (1<<ADLAR) |(0<<MUX0)| (0<<MUX1); // Смещение результата влево, Аналоговый сигнал на PB5

    unsigned char pcon; // Порог включения
    unsigned char pcoff; // Порог выключения
    unsigned int tdelay; // Время задержки
   bit flag=0;
   unsigned char v;
      
   pcon=0xFB;   //4.9*256/5; // Задать порог включения
   pcoff=0xE1;   //4.4*256/5; // Задать порог выключения
   tdelay=30000; // Задать время задержки
   temp=1; // Датчик включен
   
   PORTB|=(1<<4);
   _delay_us(50);
   
   while (1)
    {
   ADCSRA|=(1<<ADSC);   //Начать преобразование
   while (!(ADCSRA & (1<<5)));
   // loop_until_bit_is_set(ADIF); // while ((ADCSRA&_BV(ADIF))==0x00); //Дождаться окончания преобразования
   v=ADCH;

   if (v>=pcon)
   {
      PORTB|=(1<<4);
   }
   else if (v<=pcoff)
   {
      if(flag==1)
      {
         PORTB&=~(1<<4);
         flag=0;
      }
      else
      {
         _delay_ms(tdelay);
         flag=1;
      }
   }
   }
}

Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: Фотодатчик на Tiny13

Сообщение Аlex »

GRAF писал(а):

Код: Выделить всё

      if(flag==1)
      {
         PORTB&=~(1<<4);
         flag=0;
      }
      else
      {
         _delay_ms(tdelay);
         flag=1;
      }
После задержки, на следующем входе, попадаем в if, затем снова в else, там задержка, и так по-кругу... При условии "v<=pcoff" программа будет всегда находиться в 30-ти секундной задержке. Это чревато запозданием (макс. = 30 сек.) срабатывания условия "v>=pcon".
Можно добавить ещё 1 флаг, и по нему запрещать повторное вхождение в else с задержкой, а разрешать только после перехода значения выше верхней уставки. Короче, программный триггер надо сделать :)
seagull72
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вт май 04, 2010 20:05:38

Re: Фотодатчик на Tiny13

Сообщение seagull72 »

GRAF писал(а):Проверяйте, я уже спать хочу.


Спасибо, вечером проверю, на работе, боюсь, некогда будет.

Аlex писал(а):Можно добавить ещё 1 флаг, и по нему запрещать повторное вхождение в else с задержкой, а разрешать только после перехода значения выше верхней уставки. Короче, программный триггер надо сделать :)


И это посмотрю. Спасибо.

P.S. Черт побери, а ведь когда-то неплохо программировал. Правда не на С. И было это лет 20 назад.
Живём как положено. Положено на всё.
Аватара пользователя
GRAF
Мудрый кот
Сообщения: 1867
Зарегистрирован: Ср янв 23, 2008 22:11:54
Откуда: Калининград

Re: Фотодатчик на Tiny13

Сообщение GRAF »

Если лет 20 назад программировали, то, наверное, любую программу начинали с блок-схемы? Она очень помогает построить нужную логику работы.
seagull72
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вт май 04, 2010 20:05:38

Re: Фотодатчик на Tiny13

Сообщение seagull72 »

У меня сейчас главная проблема не в блок-схеме. С битовыми операциями в СИ разобраться. Записи типа PORTB|=(1<<PORTB1) пока сильно пугают, каждый раз в шпаргалку смотреть приходится. :shock:

P.S.
GRAF писал(а):Проверяйте, я уже спать хочу.


Проверил. Не работает.
Компилятор выругался "unknown type name 'bit', заменил тип на char, тогда откомпилировалось. В Протеус загнал - не работает, постоянный лог. 1 на выходе.
Может я чего не то делаю в atmel studio?
Живём как положено. Положено на всё.
ddimochka
Встал на лапы
Сообщения: 82
Зарегистрирован: Чт мар 22, 2012 20:28:49

Re: Фотодатчик на Tiny13

Сообщение ddimochka »

Строчка
pcon=4.9/5*1024; // Задать порог включения

даст значение 0,0000957. Если его записать в переменную типа unsigned int, то запишется 0. Соответственно результат преобразования всегда будет выше значения pcon.
Попробуйте скобки поставить

pcon=4.9/(5*1024); // Задать порог включения
ddimochka
Встал на лапы
Сообщения: 82
Зарегистрирован: Чт мар 22, 2012 20:28:49

Re: Фотодатчик на Tiny13

Сообщение ddimochka »

В примере присланном GRAF результат помоему тоже всегда будет больше pcon, т.к. переменная имеет 8 бит, а результат измерения 10 и результат сдвигается влево.
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Фотодатчик на Tiny13

Сообщение ARV »

seagull72 писал(а):Алгоритм такой - АЦП снимает напряжение и сравнивает его с двумя пороговыми (заданными в программе). Если напряжение превысит верхний пороговый уровень, то на выходе МК - лог. 1, если напряжение снизится ниже нижнего порогового уровня, то МК ждет 30 сек и еще раз проводит измерение напряжения, если оно и после этого ниже нижнего уровня - то на выходе лог. 0.
попробуем записать алгоритм в виде кода:

Код: Выделить всё

#include <avr/io.h>
#include <util/delay.h>

// определяем верхний порог (пока просто цифра, не имеющая отношения к сути)
#define HI_LEVEL   1000
// определяем нижний порог (условия те же)
#define LO_LEVEL   100
// определяем задержку в миллисекундах
#define DELAY   30000

static uint16_t get_adc(void); // прототип функции "опроса" датчика
static void initialize(void); // прототип функции инициализации периферии

int main(void){
   int adc; // тут будем хранить значение сигнала с датчика

   initialize(); // проинициализировали периферию

   while(1){
      adc = get_adc();
      if(adc > HI_LEVEL){
         // включаем на нужном порту 1
         continue;
      }
      if(adc < LO_LEVEL){
         // здесь можно проверить состояние порта, чтобы не ждать понапрасну, если там 0
         // если проверка покажет, что в порту 0, просто выполнить снять ремарку с continue;
         // continue;
         _delay_ms(DELAY); // ждем 30 секунд
         if(get_adc() < LO_LEVEL){
            // выключаем нужный порт
         }
      }
   }
}
проверьте: этот код на 100% соответствует заданному алгоритму?

мне кажется - да. поэтому остается совсем чуток: реализовать настройку периферии (вы уже делали, просто скопипастить) и функцию измерения (тож делали, но функцией не оформляли) и под комментарием добавить изменение уровней в порту - я не стал это делать, чтобы не путать вас и себя, это просто, надеюсь.
ну и в заключении сделать все расчеты для значений LO_VALUE и HI_VALUE калькулятором и вставить в соответствующее место значение (это если вы немного плаваете в особенностях работы с константами и выражениями в Си - а вы плаваете, как я понял)

все, задача решена.

чтобы понять, почему так, и как вообще следует поступать в подобных случаях начинающим, рекомендую ознакомиться: https://www.simple-devices.ru/articles/ ... 0-16-40-05
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Фотодатчик на Tiny13

Сообщение YS »

Код: Выделить всё

(0<<DDB3)


Сдвигать ноль бессмысленно.

Запись единицы в бит N переменной var:

Код: Выделить всё

var|=(1<<N);


сброс единицы в позиции N переменной var:

Код: Выделить всё

var&=~(1<<N);


Код: Выделить всё

DDRB=(0<<DDB5) | (1<<DDB4) | (0<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);


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

Код: Выделить всё

GIMSK=(0<<INT0) | (0<<PCIE);
MCUCR=(0<<ISC01) | (0<<ISC00);


Соответственно, эти операции эквивалентны простому присвоению нуля в соответствующие регистры. Чтобы убедиться, что в нужных битах ноль, и при этом не затронуть остальные (если вдруг так надо), следует сделать по типу описанного выше:

Код: Выделить всё

GIMSK&=~((1<<INT0) | (1<<PCIE));


Обратите внимание, каким образом записывается операция одновременного сброса нескольких битов.

Код: Выделить всё

unsigned int pcon;


Лучше использовать типы с гарантированной разрядностью из stdint.h, так как разрядность обычного типа int зависит от архитектуры.

Код: Выделить всё

_delay_ms(tdelay);


В функциях семейства _delay_xx() лучше не использовать переменные, эти функции спроектированы под константы в качестве параметра. Хотя в вашем случае компилятор скорее всего оптимизирует код, выкинув переменную tdelay.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Аватара пользователя
GRAF
Мудрый кот
Сообщения: 1867
Зарегистрирован: Ср янв 23, 2008 22:11:54
Откуда: Калининград

Re: Фотодатчик на Tiny13

Сообщение GRAF »

seagull72 писал(а):У меня сейчас главная проблема не в блок-схеме. С битовыми операциями в СИ разобраться. Записи типа PORTB|=(1<<PORTB1) пока сильно пугают, каждый раз в шпаргалку смотреть приходится. :shock:

P.S.
GRAF писал(а):Проверяйте, я уже спать хочу.

Проверил. Не работает.
Компилятор выругался "unknown type name 'bit', заменил тип на char, тогда откомпилировалось. В Протеус загнал - не работает, постоянный лог. 1 на выходе.
Может я чего не то делаю в atmel studio?


Конечно не работает, проверьте строку

Код: Выделить всё

while (!(ADCSRA & (1<<5)));


Идем дальше

Код: Выделить всё

ADMUX=(1<<REFS0) | (1<<ADLAR) |(0<<MUX0)| (0<<MUX1); // Смещение результата влево, Аналоговый сигнал на PB5

Включен внутренний ИОН в качестве опоры для АЦП. Это 1.0-1.2В. У вас делитель на входе АЦП стоит?

ddimochka писал(а):В примере присланном GRAF результат помоему тоже всегда будет больше pcon, т.к. переменная имеет 8 бит, а результат измерения 10 и результат сдвигается влево.

В примере, присланном GRAF, всё верно. Разрядность АЦП 10 бит, но результат сдвинут влево, считывание идет из ADCH. Это 8 бит, посему

Код: Выделить всё

pcon=0xFB;   //4.9*256/5; // Задать порог включения
pcoff=0xE1;   //4.4*256/5; // Задать порог выключения

Считаем сами в калькуляторе и подставляем в HEX, операции с float для тиньки тяжеловаты.

Автор, исправляйте программу по замечаниям. Она работает.
seagull72
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вт май 04, 2010 20:05:38

Re: Фотодатчик на Tiny13

Сообщение seagull72 »

Спасибо всем ответившим. Проблема, похоже, решена. Теперь буду препарировать программу. Отдельно посмотрю как работает АЦП, потом отдельно if-else, ибо подсказки и шпаргалки хорошо, но надо самому почувствовать и понять.
Живём как положено. Положено на всё.
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Фотодатчик на Tiny13

Сообщение YS »

подсказки и шпаргалки хорошо, но надо самому почувствовать и понять.


Неистово плюсую. Очень правильный подход! :beer:

Единственно что могу добавить, так это то, что экспериментировать именно с конструкциями языка удобнее на "большом" ПК, ибо коренных изменений в них при переходе к МК нет. Но об этом, я думаю, вы и сами догадываетесь. :)
Разница между теорией и практикой на практике гораздо больше, чем в теории.
seagull72
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вт май 04, 2010 20:05:38

Re: Фотодатчик на Tiny13

Сообщение seagull72 »

Итак, программа в Proteuse работает так, как надо. Непонятен остался один момент.

_delay_ms() задает задержку в миллисекундах, если я правильно понимаю. Тогда почему, чтобы получить задержку 30 сек, мне пришлось записать _delay_ms(4500), а не _delay_ms(30000)?

Частота в настройках проекта Atmel Studuo задана как F_CPU=8000000UL. Насколько я понимаю - это 8 МГц. Правильно ли это?
Живём как положено. Положено на всё.
Аватара пользователя
GRAF
Мудрый кот
Сообщения: 1867
Зарегистрирован: Ср янв 23, 2008 22:11:54
Откуда: Калининград

Re: Фотодатчик на Tiny13

Сообщение GRAF »

seagull72, идёте в раздел System Clock and Clock Options.
F_CPU=8000000UL- да, это 8МГц.
В настройках МК ATtiny13 в протеусе по умолчанию стоит частота 9.6МГц.
Кроме того, может быть выставлен предделитель тактовой частоты на 8.
seagull72
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вт май 04, 2010 20:05:38

Re: Фотодатчик на Tiny13

Сообщение seagull72 »

GRAF писал(а):идёте в раздел System Clock and Clock Options.


Это где? Даташит? Или Atmel? Извините за глупый вопрос.

GRAF писал(а):В настройках МК ATtiny13 в протеусе по умолчанию стоит частота 9.6МГц.
Кроме того, может быть выставлен предделитель тактовой частоты на 8.


Да, именно так и выставлен в Протеусе. Чем может грозить разная частота в Atmel и Proteus?
Последний раз редактировалось seagull72 Чт дек 10, 2015 20:12:18, всего редактировалось 4 раза.
Живём как положено. Положено на всё.
Аватара пользователя
GRAF
Мудрый кот
Сообщения: 1867
Зарегистрирован: Ср янв 23, 2008 22:11:54
Откуда: Калининград

Re: Фотодатчик на Tiny13

Сообщение GRAF »

Документация на ATtiny13.
Параметры для delay рассчитываются на этапе компиляции по заранее выставленной Вами частоте в AVR Studio. В протеусе Вы ставите другую частоту тактирования.
seagull72
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вт май 04, 2010 20:05:38

Re: Фотодатчик на Tiny13

Сообщение seagull72 »

А где предделитель в протеусе пишется? CKSEL fuses - это частота. SUT fuses - это оно?
Живём как положено. Положено на всё.
Аватара пользователя
GRAF
Мудрый кот
Сообщения: 1867
Зарегистрирован: Ср янв 23, 2008 22:11:54
Откуда: Калининград

Re: Фотодатчик на Tiny13

Сообщение GRAF »

С английским у Вас как? CLKDIV8.
seagull72
Нашел транзистор. Понюхал.
Сообщения: 167
Зарегистрирован: Вт май 04, 2010 20:05:38

Re: Фотодатчик на Tiny13

Сообщение seagull72 »

Пока неважно с английским, но это поправится скоро.

Стоит (0)Programmed - то есть задается в программе. Стоял бы (1)Unprogrammed - был бы включен предделитель принудительно. Я правильно понимаю?
Все, разобрался. Ровно наоборот.
Последний раз редактировалось seagull72 Чт дек 10, 2015 20:23:01, всего редактировалось 1 раз.
Живём как положено. Положено на всё.
Ответить

Вернуться в «AVR»