Перейти к содержанию

Таймер обратного отсчета


S1mpleX

Рекомендуемые сообщения

Здравствуйте!
Помогите мне пожалуйста, я начинающий в МК и вот пишу свой первый, немножечко "серьезный" проект и никак не могу добиться работоспособности((
Суть в следующем:
Таймер после нажатия на кнопку "старт/стоп"запускает обратный отсчет (по умолчанию от 300 секунд), кнопками +10 и -10, изменяется время по 10 сек. Во время работы я хочу считывать регистр АЦП и писать его в регистр таймера (ШИМ, который управляет двигателем), оставшееся или установленное время отображается на 3х разрядном индикаторе, после достижения ноля хочу в регистр ШИМа писать ноли и останавливать двигатель.
Но сколько уже не играюсь - оно не работает в протеусе((
Очень очень сильно прошу помощи, а то уже и охота пропадает заниматься(((
Заранее спасибо! Проект протеуса и код в Atmel Studio прилагаю. MK - ATMega8

#define F_CPU 8000000
#define ADC_VREF_TYPE ((0<<REFS1) | (1<<REFS0) | (0<<ADLAR))
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

unsigned char codes[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xD8, 0x80, 0x90};
volatile int dig = 1;			  //Номер разряда
volatile int seconds = 300;       //Выводимые данные
char Timeout;
char Start;
int adc_result;

void IO_init(void){
	//_IO_Init
	// Port B initialization
	// Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=In Bit1=In Bit0=In
	DDRB=(1<<DDB7) | (1<<DDB6) | (1<<DDB5) | (1<<DDB4) | (1<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
	// State: Bit7=0 Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=P Bit1=P Bit0=P
	PORTB=(0<<PORTB7) | (0<<PORTB6) | (0<<PORTB5) | (0<<PORTB4) | (0<<PORTB3) | (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);

	// Port C initialization
	// Function: Bit6=Reset Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=In
	DDRC=(0<<DDC6) | (1<<DDC5) | (1<<DDC4) | (1<<DDC3) | (1<<DDC2) | (1<<DDC1) | (0<<DDC0);
	// State: Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=T
	PORTC=(0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);

	// Port D initialization
	// Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
	DDRD=(1<<DDD7) | (1<<DDD6) | (1<<DDD5) | (1<<DDD4) | (1<<DDD3) | (1<<DDD2) | (1<<DDD1) | (1<<DDD0);
	// State: Bit7=0 Bit6=1 Bit5=1 Bit4=1 Bit3=1 Bit2=1 Bit1=1 Bit0=1
	PORTD=(0<<PORTD7) | (1<<PORTD6) | (1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3) | (1<<PORTD2) | (1<<PORTD1) | (1<<PORTD0);
		
}

unsigned int read_adc(void)
{
	unsigned int adc_result;
	ADMUX &= (~(1<<MUX0)) | (~(1<<MUX1)) | (~(1<<MUX2)) | (~(1<<MUX3)) | ADC_VREF_TYPE;
	_delay_us(10);
	ADCSRA|=(1<<ADSC);
	while ((ADCSRA & (1<<ADIF))==0);
	ADCSRA|=(1<<ADIF);
	adc_result=(ADCL|ADCH<<8);
	return adc_result;
}

void ind_timer_init(void)
	{
		TIMSK = (1 << TOIE0);       //Разрешить прерывание таймера по переполнению
		TCCR0 = (1 << CS01);        //Предделитель - 8
	}

void PWM_timer_init(void){
	// Timer/Counter 2 initialization
	// Clock source: System Clock
	// Clock value: 31,250 kHz
	// Mode: Fast PWM top=0xFF
	// OC2 output: Non-Inverted PWM
	// Timer Period: 8,192 ms
	// Output Pulse(s):
	// OC2 Period: 8,192 ms Width: 0 us
	ASSR=0<<AS2;
	TCCR2=(1<<WGM20) | (1<<COM21) | (0<<COM20) | (1<<WGM21) | (1<<CS22) | (1<<CS21) | (0<<CS20);
	TCNT2=0x00;
	OCR2=0x00;
}

void RTC_timer_init(void){
	 TCCR1A = 0;			 // настройка таймера 1, канала А
	 TCCR1B |= (1<<CS12);			 // предделитель CLK/256;
	 OCR1A = 0x7A11;		 // прерывание раз в секунду
	 TIMSK &= (~(1<<OCIE1A));	// прерывание таймера откл
}


/************************************************************************/
/*                          INTERRUPT'S PART                            */
/************************************************************************/
ISR (TIMER0_OVF_vect)
{
	PORTD = 0xFF;       //Выключаем все сегменты
	PORTC = (1 << dig);
	switch(dig)
	{
		case 1: PORTD = (codes[seconds % 1000 / 100]); break;          //Раскладываем число на разряды
		case 2: PORTD = (codes[seconds % 100 / 10]); break;
		case 3: PORTD = (codes[seconds % 10]); break;
	}
	if ((dig++) > 2) dig = 1;
}

ISR(TIMER1_COMPA_vect)
{
	Timeout = 1;
	seconds--;
	if (seconds < 1) {
		Start=0;
		TIMSK &= (~(1<<OCIE1A));
	}
}
	
int main()
{
	IO_init(); 
	ind_timer_init();
	RTC_timer_init();
	read_adc;
	sei();
			
	while(1)
	{
		if (!PINB2)
		{
			_delay_ms(50);
			if (!PINB2)
			{
				Start ^= 1;
				TCNT1 = 0;
				TIMSK |= (1<<OCIE1A);
			}
		}
		if (!PINB1)
		{
			_delay_ms(50);
			if (!PINB1)
			{
				seconds+=10;
			}
		}
		if (!PINB0)
		{
			_delay_ms(50);
			if (!PINB0)
			{
				seconds-=10;
			}
		}
		
		while(Start)
		{
			Timeout = 0;
			OCR2 = adc_result;
			while(!Timeout);
		}
						
	}
}

 

321.pdsprj


 

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

6 часов назад, Alex сказал:

Что означает "не работает" ? Что конкретно не работает ?
 

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


 

Ссылка на комментарий
Поделиться на другие сайты

13 часа назад, S1mpleX сказал:

При старте сразу же начинается отсчет, при чем секунд длится дольше (с частотой все ок), либо просто вычитается по 10 секунд, не останавливается в нуле 

Заметил сразу две ошибки :

1) Флаг обрабатывающий только одно нажатие . При нажатии у Вас может произойти установка не +10сек или -10 сек за одно нажатие, а сразу +20,+30 сек и соответственно -20,-30 сек.

2) Ограничение переменных +10/-10 сек. они могут выйти за пределы допустимого .

Что может быть лучше в радиоэлектронике, чем программирование микроконтроллеров ?

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, artos5 сказал:

Заметил сразу две ошибки :

1) Флаг обрабатывающий только одно нажатие . При нажатии у Вас может произойти установка не +10сек или -10 сек за одно нажатие, а сразу +20,+30 сек и соответственно -20,-30 сек.

2) Ограничение переменных +10/-10 сек. они могут выйти за пределы допустимого .

Спасибо, а где по коду это?


 

Ссылка на комментарий
Поделиться на другие сайты

Только что, Alex сказал:

Хм... Как тогда можно не понимать, как работает собственный код ? :huh:


 

я понимаю ка он должен работать, но не понимаю, почему так не происходит


 

Ссылка на комментарий
Поделиться на другие сайты

В 19.06.2017 в 21:46, S1mpleX сказал:

if (!PINB2)

А, простите, чего вы хотели добиться выражением if( ! 2 ), полностью эквивалентному процитированному? Это вам не cvavr где есть извращения вроде PINB.2

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

29 минут назад, COKPOWEHEU сказал:

А, простите, чего вы хотели добиться выражением if( ! 2 ), полностью эквивалентному процитированному? Это вам не cvavr где есть извращения вроде PINB.2

Atmel Studio понимает это, на сколько я знаю, она сама предложила такую запись


 

Ссылка на комментарий
Поделиться на другие сайты

Эта запись вполне корректна с точки зрения языка. Вот только бесполезна, поскольку PINB2 это константа, равная 2.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

26 минут назад, COKPOWEHEU сказал:

Эта запись вполне корректна с точки зрения языка. Вот только бесполезна, поскольку PINB2 это константа, равная 2.

Почему? И как тогда правильно опрашивать пин? Спасибо


 

Ссылка на комментарий
Поделиться на другие сайты

Почему? С одной стороны, так оно объявлено в avr/iom8.h (наверное). С другой стороны, в Си нет прямой работы с отдельными битами переменной - только через логические операции.

Традиционно используются подобные записи:

PORTA |= (1<<0);
PORTB &=~(1<<1);
if( PINC & (1<<2) ){...}
if( ! (PIND & (1<<3)) ){...}

Рекомендую составить таблицы истинности и разобраться какая из записей что делает. Подсказка: каждая из них работает с одним битом.

Когда разберетесь, можете глянуть мои макросы (pinmacro.h в моей подписи) и использовать более наглядные и переносимые записи вроде

#define BUTTON E,4,0 //кнопка на PE4, замыкается на землю
DDR_1( BUTTON ); //включить подтяжку кнопки к питанию
if( PIN_ON( BUTTON) ){...}

Но для этого надо хорошо разбираться в битовой и макросной магии.

.

Помимо прочего, рекомендую разобраться с правильным опросом кнопок. Самое простое - просто регулярно опрашивать с частотой около 10 Гц, в бесконечном цикле или по таймеру. Другой вариант - отлавливать фронты: запоминать предыдущее состояние кнопки в переменной и сравнивать с текущим, но тут возникают проблемы с дребезгом.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

6 часов назад, COKPOWEHEU сказал:

Почему? С одной стороны, так оно объявлено в avr/iom8.h (наверное). С другой стороны, в Си нет прямой работы с отдельными битами переменной - только через логические операции.

Традиционно используются подобные записи:


PORTA |= (1<<0);
PORTB &=~(1<<1);
if( PINC & (1<<2) ){...}
if( ! (PIND & (1<<3)) ){...}

Рекомендую составить таблицы истинности и разобраться какая из записей что делает. Подсказка: каждая из них работает с одним битом.

Когда разберетесь, можете глянуть мои макросы (pinmacro.h в моей подписи) и использовать более наглядные и переносимые записи вроде


#define BUTTON E,4,0 //кнопка на PE4, замыкается на землю
DDR_1( BUTTON ); //включить подтяжку кнопки к питанию
if( PIN_ON( BUTTON) ){...}

Но для этого надо хорошо разбираться в битовой и макросной магии.

.

Помимо прочего, рекомендую разобраться с правильным опросом кнопок. Самое простое - просто регулярно опрашивать с частотой около 10 Гц, в бесконечном цикле или по таймеру. Другой вариант - отлавливать фронты: запоминать предыдущее состояние кнопки в переменной и сравнивать с текущим, но тут возникают проблемы с дребезгом.

Таймеры у меня заняты, поэтому так и хочу записать


 

Ссылка на комментарий
Поделиться на другие сайты

Только что, S1mpleX сказал:

Таймеры у меня заняты

Неужели так заняты, что опрос порта не смогут делать?

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

6 минут назад, ARV сказал:

Неужели так заняты, что опрос порта не смогут делать?

Не знаю, я еще не очень разбираюсь, поэтому и пишу сюда

Сейчас у меня просто сразу же после включения стартует отсчет, при чем с частотой явно меньшей секунды, на кнопки не реагирует


 

Ссылка на комментарий
Поделиться на другие сайты

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


 

Ссылка на комментарий
Поделиться на другие сайты

20 минут назад, Alex сказал:

Частота камня не совпадает с ожидаемой ?
 

Совпадает, первая секунда идет четко, а потом все равно что замедленно в 2 раза, как будто прерывания индикации отодвигают прерывание счетчика секунд, хотя приоритет его выше


 

Ссылка на комментарий
Поделиться на другие сайты

С отсчетом времени у вас тоже накручено что-то непонятное. Я бы повесил на T2 (раз он умеет асинхронный счет) отсчет времени. А на T1 - ШИМ: у него и разрядность выше, и два канала выведены, и режимов больше.

volatile uint16_t time_s = 0;

ISR(TIMER2_COMP_vect){ //F_Timer2 = F_CPU/256 (CS22:CS20 = 0b110) ; OCR2 = 250
  static uint8_t frac_sec = 0;
  frac_sec++;
  if( frac_sec >= 125 ){
    frac_sec = 0;
    time_s ++;
  }
}

Константы (делитель на 256, аппаратный счет до 250 и программный до 125) выбраны чтобы при тактовой частоте 8 МГц переменная time_s менялась раз в секунду.

В этот же обработчик можно добавить динамическую индикацию. Только реализовав по-нормальному, а не как в коде в 1 посте. Разложение на разряды делается не при каждом выводе, а только при изменении. То есть заводится буфер кадра в котором хранятся сразу коды для вывода на индикатор/

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

7 часов назад, Alex сказал:

В 8-ой Меге нет приоритетов. Все прерывания встают в очередь и будут ждать пока не обработается другое работающее.
 

Спасибо вам!

2 часа назад, COKPOWEHEU сказал:

С отсчетом времени у вас тоже накручено что-то непонятное. Я бы повесил на T2 (раз он умеет асинхронный счет) отсчет времени. А на T1 - ШИМ: у него и разрядность выше, и два канала выведены, и режимов больше.


volatile uint16_t time_s = 0;

ISR(TIMER2_COMP_vect){ //F_Timer2 = F_CPU/256 (CS22:CS20 = 0b110) ; OCR2 = 250
  static uint8_t frac_sec = 0;
  frac_sec++;
  if( frac_sec >= 125 ){
    frac_sec = 0;
    time_s ++;
  }
}

Константы (делитель на 256, аппаратный счет до 250 и программный до 125) выбраны чтобы при тактовой частоте 8 МГц переменная time_s менялась раз в секунду.

В этот же обработчик можно добавить динамическую индикацию. Только реализовав по-нормальному, а не как в коде в 1 посте. Разложение на разряды делается не при каждом выводе, а только при изменении. То есть заводится буфер кадра в котором хранятся сразу коды для вывода на индикатор/

Огромное спасибо! попробую поменять таймеры, а можете так же показать пример как корректно организовать индикацию?

И вот еще вопрос, разве тогда не будет все равно ждать обработки прерывания таймера2, после обработки прерывания индикации?


 

Ссылка на комментарий
Поделиться на другие сайты

Прерывания достаточно короткие (или должны быть короткими) и успеют завершиться за 1/125 секунды (64000 тактов). По крайней мере не придется следить за тем какой таймер запущен а какой остановлен.
 

#define SEG_A (1<<3)
#define SEG_B (1<<6)
...
const uint8_t seg[] = { //коды цифр (для примера, зажигаются при подаче лог.1)
  SEG_A | SEG_B | SEG_C | SEG_D | SEG_E | SEG_F, //0
  SEG_B | SEG_C, //1
...
};
//для примера, пусть 3 разряда
#define DIGIT_1 (1<<2)
#define DIGIT_2 (1<<4)
#define DIGIT_3 (1<<6)
const uint8_t digits[3] = {DIGIT_1, DIGIT_2, DIGIT_3}; //коды разрядов (для примера, активный уровень - лог.0, то есть индикаторы с общим катодом)
#define PORT_SEG PORTA
#define PORT_DIGIT PORTB

volatile uint8_t videobuffer[3];

//отображение следующего разряда. Вызывать в основном цикле или по таймеру
inline void dyn_ind(){
  static uint8_t cur_digit = 0;
  PORT_SEG = 0; //гасим все сегменты чтобы на следующем не было засвета от предыдущего
  cur_digit++;
  if(cur_digit > 3)cur_digit=0;
  PORT_DIGIT |= DIGIT_1 | DIGIT_2 | DIGIT_3; //отключаем все разряды (поскольку активный уровень лог.0, то гасим записью лог.1)
  PORT_DIGIT &=~ digits[ cur_digit ]; //зажигаем (выставляем в лог.0) только текущий разряд
  PORT_SEG = videobuffer[ cur_digit ]; //зажигаем текущий символ
}

//вывод на индикатор целого числа
void out_byte(uint8_t x){
  videobuffer[2] = seg[ x % 10 ]; //сразу перевод из цифры в код символа, чтобы меньше вычислений делалось в процедуре индикации
  x /= 10;
  videobuffer[1] = seg[ x % 10 ];
  videobuffer[0] = seg[ x / 10 ];
}

Более универсальная версия есть у меня в подписи - 7seg.h

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
  • Сообщения

    • Нет, изначально планировал дальний в полнакала, развел плату, заказал в Китае 5шт (первый заказ, скидки и просто красиво). Установка планировалась в семейный "парк" авто. Конечно, если все будет работать правильно, то каким-то знакомым или знакомым знакомых можно и сделать.  Но, как оказалось, есть куча нюансов. Потом присмотрел ДХО с режимом поворотника такого плана:   Как уже ранее писал, для ледов девайс можно перевести в режим реле. Но поскольку обычно в подобных лампах все на пределе по току и по нагреву, и живут они соответственно не долго,  хотелось бы оставить возможность ШИМ. Вот и интересно как реагирует светодиод на ШИМ. Пока ясно, что нужно поднять частоту. Может еще электролит по выходу добавить или нет особого смысла?  
    • Тут подробнее. Становится понятно что бета величина нифига не линейная.  
    • И что тут я должен сравнивать ? На последнем фото моя плата, сравните с видеороликом. В однофазной мотор подключается непосредственно к плате, в трёхфазной версии мотор подключается через контактор, а реле контактора подключаются к out motor (на L/S и N/R)  Если вы не верите, то я могу запустить плату и сделать фото загрузки блока, где на экране будет видна модель устройства... Или вы будете утверждать ещё и факт перепрошивки ?
    • Собственно вопрос - как увеличить выходной ток заряда? Вот в этой схеме какой именно резистор нужно подобрать для изменения тока заряда?  
    • @Ашот Чобанян Мда.... 1. Вы серьезно считаете что все частотники одинаковые и все вам отвечающие обладают экстрасенсорными способностями что бы узнать их модели через экран? 2. У частотников (ВНЕЗАПНО!!!) есть в комплекте такая вещь как инструкция. Говорят что в них открывают тайны их монтажа и подключения. 3. Если вы не смогли сами, поищите в ближнем своем окружении человека, который сможет. Есть большая вероятность что вам это будет стоить дешевле, чем несколько поломанных частотников, или поломанное оборудование.
    • Там же написано, при токе 1 ампер и 7 ампер. Практически, на токах до пары ампер 90 - 120
    • Вроде оригинал на вид но я не эксперт в распознании оригиналов и подделок,ещё не встречал что бы на СССР микросхемы поделки были современные  Можете этот пост разместить в тему где распознают оригинал запчасти от подделок,вроде называеться "Подделки на которые нарвались",там быстрее ответят 
×
×
  • Создать...