Фотодатчик на Tiny13
Фотодатчик на Tiny13
Доброго времени суток.
Это моя первая попытка разобраться в микроконтроллерах, так что прошу сильно не пинать, а, наоборот, помочь по возможности.
Итак. 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);
}
}
И сама программа:
Это моя первая попытка разобраться в микроконтроллерах, так что прошу сильно не пинать, а, наоборот, помочь по возможности.
Итак. 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 скачиваний
Живём как положено. Положено на всё.
Re: Фотодатчик на Tiny13
Проверяйте, я уже спать хочу.
Код: Выделить всё
/*
* 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
После задержки, на следующем входе, попадаем в if, затем снова в else, там задержка, и так по-кругу... При условии "v<=pcoff" программа будет всегда находиться в 30-ти секундной задержке. Это чревато запозданием (макс. = 30 сек.) срабатывания условия "v>=pcon".GRAF писал(а):Код: Выделить всё
if(flag==1)
{
PORTB&=~(1<<4);
flag=0;
}
else
{
_delay_ms(tdelay);
flag=1;
}
Можно добавить ещё 1 флаг, и по нему запрещать повторное вхождение в else с задержкой, а разрешать только после перехода значения выше верхней уставки. Короче, программный триггер надо сделать
Re: Фотодатчик на Tiny13
GRAF писал(а):Проверяйте, я уже спать хочу.
Спасибо, вечером проверю, на работе, боюсь, некогда будет.
Аlex писал(а):Можно добавить ещё 1 флаг, и по нему запрещать повторное вхождение в else с задержкой, а разрешать только после перехода значения выше верхней уставки. Короче, программный триггер надо сделать
И это посмотрю. Спасибо.
P.S. Черт побери, а ведь когда-то неплохо программировал. Правда не на С. И было это лет 20 назад.
Живём как положено. Положено на всё.
Re: Фотодатчик на Tiny13
Если лет 20 назад программировали, то, наверное, любую программу начинали с блок-схемы? Она очень помогает построить нужную логику работы.
Re: Фотодатчик на Tiny13
У меня сейчас главная проблема не в блок-схеме. С битовыми операциями в СИ разобраться. Записи типа PORTB|=(1<<PORTB1) пока сильно пугают, каждый раз в шпаргалку смотреть приходится. 
P.S.
Проверил. Не работает.
Компилятор выругался "unknown type name 'bit', заменил тип на char, тогда откомпилировалось. В Протеус загнал - не работает, постоянный лог. 1 на выходе.
Может я чего не то делаю в atmel studio?
P.S.
GRAF писал(а):Проверяйте, я уже спать хочу.
Проверил. Не работает.
Компилятор выругался "unknown type name 'bit', заменил тип на char, тогда откомпилировалось. В Протеус загнал - не работает, постоянный лог. 1 на выходе.
Может я чего не то делаю в atmel studio?
Живём как положено. Положено на всё.
Re: Фотодатчик на Tiny13
Строчка
pcon=4.9/5*1024; // Задать порог включения
даст значение 0,0000957. Если его записать в переменную типа unsigned int, то запишется 0. Соответственно результат преобразования всегда будет выше значения pcon.
Попробуйте скобки поставить
pcon=4.9/(5*1024); // Задать порог включения
pcon=4.9/5*1024; // Задать порог включения
даст значение 0,0000957. Если его записать в переменную типа unsigned int, то запишется 0. Соответственно результат преобразования всегда будет выше значения pcon.
Попробуйте скобки поставить
pcon=4.9/(5*1024); // Задать порог включения
Re: Фотодатчик на Tiny13
В примере присланном GRAF результат помоему тоже всегда будет больше pcon, т.к. переменная имеет 8 бит, а результат измерения 10 и результат сдвигается влево.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Фотодатчик на Tiny13
попробуем записать алгоритм в виде кода: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){
// выключаем нужный порт
}
}
}
}мне кажется - да. поэтому остается совсем чуток: реализовать настройку периферии (вы уже делали, просто скопипастить) и функцию измерения (тож делали, но функцией не оформляли) и под комментарием добавить изменение уровней в порту - я не стал это делать, чтобы не путать вас и себя, это просто, надеюсь.
ну и в заключении сделать все расчеты для значений LO_VALUE и HI_VALUE калькулятором и вставить в соответствующее место значение (это если вы немного плаваете в особенностях работы с константами и выражениями в Си - а вы плаваете, как я понял)
все, задача решена.
чтобы понять, почему так, и как вообще следует поступать в подобных случаях начинающим, рекомендую ознакомиться: https://www.simple-devices.ru/articles/ ... 0-16-40-05
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Фотодатчик на Tiny13
Код: Выделить всё
(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.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Re: Фотодатчик на Tiny13
seagull72 писал(а):У меня сейчас главная проблема не в блок-схеме. С битовыми операциями в СИ разобраться. Записи типа PORTB|=(1<<PORTB1) пока сильно пугают, каждый раз в шпаргалку смотреть приходится.
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 для тиньки тяжеловаты.
Автор, исправляйте программу по замечаниям. Она работает.
Re: Фотодатчик на Tiny13
Спасибо всем ответившим. Проблема, похоже, решена. Теперь буду препарировать программу. Отдельно посмотрю как работает АЦП, потом отдельно if-else, ибо подсказки и шпаргалки хорошо, но надо самому почувствовать и понять.
Живём как положено. Положено на всё.
Re: Фотодатчик на Tiny13
подсказки и шпаргалки хорошо, но надо самому почувствовать и понять.
Неистово плюсую. Очень правильный подход!
Единственно что могу добавить, так это то, что экспериментировать именно с конструкциями языка удобнее на "большом" ПК, ибо коренных изменений в них при переходе к МК нет. Но об этом, я думаю, вы и сами догадываетесь.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Re: Фотодатчик на Tiny13
Итак, программа в Proteuse работает так, как надо. Непонятен остался один момент.
_delay_ms() задает задержку в миллисекундах, если я правильно понимаю. Тогда почему, чтобы получить задержку 30 сек, мне пришлось записать _delay_ms(4500), а не _delay_ms(30000)?
Частота в настройках проекта Atmel Studuo задана как F_CPU=8000000UL. Насколько я понимаю - это 8 МГц. Правильно ли это?
_delay_ms() задает задержку в миллисекундах, если я правильно понимаю. Тогда почему, чтобы получить задержку 30 сек, мне пришлось записать _delay_ms(4500), а не _delay_ms(30000)?
Частота в настройках проекта Atmel Studuo задана как F_CPU=8000000UL. Насколько я понимаю - это 8 МГц. Правильно ли это?
Живём как положено. Положено на всё.
Re: Фотодатчик на Tiny13
seagull72, идёте в раздел System Clock and Clock Options.
F_CPU=8000000UL- да, это 8МГц.
В настройках МК ATtiny13 в протеусе по умолчанию стоит частота 9.6МГц.
Кроме того, может быть выставлен предделитель тактовой частоты на 8.
F_CPU=8000000UL- да, это 8МГц.
В настройках МК ATtiny13 в протеусе по умолчанию стоит частота 9.6МГц.
Кроме того, может быть выставлен предделитель тактовой частоты на 8.
Re: Фотодатчик на Tiny13
GRAF писал(а):идёте в раздел System Clock and Clock Options.
Это где? Даташит? Или Atmel? Извините за глупый вопрос.
GRAF писал(а):В настройках МК ATtiny13 в протеусе по умолчанию стоит частота 9.6МГц.
Кроме того, может быть выставлен предделитель тактовой частоты на 8.
Да, именно так и выставлен в Протеусе. Чем может грозить разная частота в Atmel и Proteus?
Последний раз редактировалось seagull72 Чт дек 10, 2015 20:12:18, всего редактировалось 4 раза.
Живём как положено. Положено на всё.
Re: Фотодатчик на Tiny13
Документация на ATtiny13.
Параметры для delay рассчитываются на этапе компиляции по заранее выставленной Вами частоте в AVR Studio. В протеусе Вы ставите другую частоту тактирования.
Параметры для delay рассчитываются на этапе компиляции по заранее выставленной Вами частоте в AVR Studio. В протеусе Вы ставите другую частоту тактирования.
Re: Фотодатчик на Tiny13
А где предделитель в протеусе пишется? CKSEL fuses - это частота. SUT fuses - это оно?
Живём как положено. Положено на всё.
Re: Фотодатчик на Tiny13
С английским у Вас как? CLKDIV8.
Re: Фотодатчик на Tiny13
Пока неважно с английским, но это поправится скоро.
Стоит (0)Programmed - то есть задается в программе. Стоял бы (1)Unprogrammed - был бы включен предделитель принудительно. Я правильно понимаю?
Все, разобрался. Ровно наоборот.
Стоит (0)Programmed - то есть задается в программе. Стоял бы (1)Unprogrammed - был бы включен предделитель принудительно. Я правильно понимаю?
Все, разобрался. Ровно наоборот.
Последний раз редактировалось seagull72 Чт дек 10, 2015 20:23:01, всего редактировалось 1 раз.
Живём как положено. Положено на всё.