Програмирование двухрежимной работы микроконтроллера.

Обсуждаем контроллеры компании Atmel.
Ответить
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

DDRA4 = 1; //Так можно сделать порт А4 на вход?
Нет. В cvavr можно DDRA.4=1, но обычный Си такого не поддерживает.
float Kvant;
float Sec;
float Min;
float Hour;
Использовать дробные числа - плохая идея. Нет, я понимаю, 16 кБайт флеша хочется чем-то занять, но можно ведь придумать что-то полезное.
DDRA4 = 1; //Так можно сделать порт А4 на вход?
DDRA |=(1<<4); //А на такую запись он и ругается.
void main (void){
Еще бы он не ругался! Вы же вставляете операторы между функциями. Это не ассемблер где инструкцию можно запихнуть куда угодно, хоть в EEPROM (правда, выполняться она откуда попало все равно не будет), Си требует чтобы весь код находился в функциях.
Может, все-таки стоит ознакомиться с языком Си отдельно от контроллеров? Хорошо бы еще с контроллерами отдельно от Си.
-O1
в makrfile'е. Это не ошибка, просто обычно используется -Os.
Ну и в AVRStudio4.x была возможность добавлять в makefile свои флаги, в настройках компилятора, кажется. Попробуйте добавить флаг -DF_CPU=1000000UL, это укажет компилятору тактовую частоту контроллера, в этом примере 1000000 Гц = 1 МГц. Некоторые указывают частоту прямо в файле исходного кода (вроде main.c), но по-моему это добавляет больше проблем.
Фузы я не знаю, что такое :oops:
Тогда пока и не трогайте. Если и не трогали, достаточно написать "фузы по умолчанию". Вот если выпаяли контроллер из какого-то устройства будет сложнее.
Реклама
Встал на лапы
Сообщения: 131
Зарегистрирован: Вс май 08, 2016 22:45:48

Сообщение sTRog »

Спасибо за мудрые наставления, но я пока попробую по простому.
Вот написал код, посмотрите, оцените, дайте рекомендации, пожалуйста. Может увидите ошибки.
Спойлер

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

#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>



int Kvant = 0;
int Sec = 0;
char mod = 0;



void main (void)
{
	while (1)
	{
		DDRA |=(1<<4); //транзистор
		DDRA |=(1<<3); //cветодиод
		DDRB &=~(1<<4); //кнопка
		PORTB |=(1<<4); //сопротивление кнопки
		
		if (mod==0) //если первый режим включен, то когда прошедшее время равно RandTime - подаем напряжение на ножку.
		{
			int RandTime = 3600 + random()%3600;
			if (Sec>=RandTime)
			{
				PORTA |= (1<<4);
				_delay_ms(3000);
				PORTA &=~(1<<4);
				Sec = 0;
			}
		} 
		else //если второй режим включен, то когда прошедшее время равно FixTime - подаем напряжение на ножку.
		{
			int FixTime = 5400;
			if (Sec>=FixTime)
			{
				PORTA |= (1<<4);
				_delay_ms(3000);
				PORTA &=~(1<<4);
				Sec = 0;
			}
		}
		
		Kvant++; //Добавляем каждый такт по 1 милисекунде, пока не дойдет до секунды.
		if (Kvant==1000) 
		{
			Kvant = 0;
			Sec++;
		}
		
		if (PINB & (1<<4)) //Если на ножке есть напряжение то:
		{
			if (mod==0) //Если включен режим 0, меняем его на 1
			{
				mod = 1;
				
				Kvant = 0; //обнуляем время
				Sec = 0;
				
				PORTA |= (1<<3); //Если включился режим 1 - то лампочка загорится на 1 сек.
				_delay_ms(1000);
				PORTA &=~(1<<3);
				
			} 
			else //Если включен 1 режим, меняем его на 0
			{
				mod = 0;
				
				Kvant = 0; //обнуляем время
				Sec = 0;
				
				PORTA |= (1<<3); //Если включился режим 0 - то лампочка загорится на 3 сек.
				_delay_ms(3000);
				PORTA &=~(1<<3);
			}
		}
	}
}
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

while (1)
{
DDRA |=(1<<4); //транзистор
DDRA |=(1<<3); //cветодиод
DDRB &=~(1<<4); //кнопка
PORTB |=(1<<4); //сопротивление кнопки
Обычно настройки проводятся до входа в бесконечный цикл. Не то чтобы это ошибка, но зачем повторять эти действия каждый раз?
if (mod==0) //если первый режим включен, то когда прошедшее время равно RandTime - подаем напряжение на ножку.
{
int RandTime = 3600 + random()%3600;
У вас при каждом повторении бесконечного цикла переменная RandTime будет создаваться заново с новым значением. Логичнее было бы вынести за пределы блока сравнения.
Kvant++; //Добавляем каждый такт по 1 милисекунде, пока не дойдет до секунды.
А откуда уверенность что 1 такт равен 1 мс?
Встал на лапы
Сообщения: 131
Зарегистрирован: Вс май 08, 2016 22:45:48

Сообщение sTRog »

А если я со временем поступлю так?
Спойлер

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

#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <stdio.h>
#include <avr/interrupt.h>


int Pause = 0;
int Kvant = 0;
int Sec = 0;
char mod = 0;


ISR (TIMER0_COMP_vect) //получается - каждые 20 милисекунд добавляю по еденице переменным.
{
	Kvant++;
	
	if (Kvant>=50) //Добавляем каждый по секунде в переменную.
	{
		Kvant = 0;
		Sec++;
	}
}


void main (void)
{
	OCR0 = 200; //сброс при совпадении с 200, преддилитель 64, разрешение уходить в вектор при прирывании. - блок настройки таймера.
	TCCR0 = 0b00001011;
	TIMSK |=(1<<1);
	
	DDRA |=(1<<4); //транзистор
	DDRA |=(1<<3); //cветодиод
	DDRB &=~(1<<4); //кнопка
	PORTB |=(1<<4); //сопротивление кнопки
	
	while (1)
	{
		
		if (mod==0) //если первый режим включен, то когда прошедшее время равно RandTime - подаем напряжение на ножку.
		{
			int RandTime = 3600 + random()%3600;
			if (Sec>=RandTime)
			{
				PORTA |= (1<<4);
				_delay_ms(3000);
				PORTA &=~(1<<4);
				Sec = 0;
			}
		} 
		else //если второй режим включен, то когда прошедшее время равно FixTime - подаем напряжение на ножку.
		{
			int FixTime = 5400;
			if (Sec>=FixTime)
			{
				PORTA |= (1<<4);
				_delay_ms(3000);
				PORTA &=~(1<<4);
				Sec = 0;
			}
		}
		
		
		if (PINB & (1<<4)) //Если на ножке есть напряжение то:
		{
			if (mod==0) //Если включен режим 0, меняем его на 1
			{
				mod = 1;
				
				Kvant = 0; //обнуляем время
				Sec = 0;
				
				PORTA |= (1<<3); //Если включился режим 1 - то лампочка загорится на 1 сек.
				_delay_ms(1000);
				PORTA &=~(1<<3);
				
			} 
			else //Если включен 1 режим, меняем его на 0
			{
				mod = 0;
				
				Kvant = 0; //обнуляем время
				Sec = 0;
				
				PORTA |= (1<<3); //Если включился режим 0 - то лампочка загорится на 3 сек.
				_delay_ms(3000);
				PORTA &=~(1<<3);
			}
		}
	}
}
Так можно сделать? Получится то, что я хочу или я накосячил? :)
Реклама
Эиком - электронные компоненты и радиодетали
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Накосячил наверняка, какая же программа без косяков? :)
Переменную Kvant (лучше все-таки использовать перевод - quantum - а не транслитерацию) надо объявить volatile чтобы изменение ее внутри прерывания было предсказуемым. Но лучше объявить ее внутри прерывания как static. Тогда она не будет видна снаружи прерывания. Ну и раз отсчет идет до 50, какой смысл объявлять переменную как int? Ну и в Си принято именовать переменные со строчной буквы.
Переменную sec стоит объявить volatile.
TCCR0 = 0b00001011;
TIMSK |=(1<<1);
Используйте сдвиги, логические операции и стандартные имена битов, например, TIMSK = (1<<OCIE0);
Еще стоит разрешить прерывания командой sei().
int RandTime = 3600 + random()%3600;
Не исправлено.
if (mod==0) //Если включен режим 0, меняем его на 1
{
mod = 1;

Kvant = 0; //обнуляем время
А нужно здесь обнулять Kvant? Разница в среднем в полсекунды, особенно на рандомной задержке так существенна?
.
Это что заметно на первый взгляд. Попробуйте просимулировать в протеусе, он покажет часть багов.
Реклама
Встал на лапы
Сообщения: 131
Зарегистрирован: Вс май 08, 2016 22:45:48

Сообщение sTRog »

COKPOWEHEU писал(а):Тогда она не будет видна снаружи прерывания
Так мне же наоборот нужно, чтобы она глобально сбросилась в ноль, а если я статик объявлю, то она будет только внутри прерывания изменяться?
COKPOWEHEU писал(а):Цитата:
int RandTime = 3600 + random()%3600;
Не исправлено.
Так вы же сказали не обязательно исправлять, а так не видно разницы, будет обрабатываться раз за цикл так же, как если я вынес бы.
COKPOWEHEU писал(а):Еще стоит разрешить прерывания командой sei().
asm ("sei"); - достаточно впихнуть в main?
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

Так мне же наоборот нужно, чтобы она глобально сбросилась в ноль, а если я статик объявлю, то она будет только внутри прерывания изменяться?
Зачем? Чем меньше глобальных переменных тем сложнее ошибиться. Неужели вам так критична ошибка в секунду?
Так вы же сказали не обязательно исправлять, а так не видно разницы, будет обрабатываться раз за цикл так же, как если я вынес бы.
Эта переменная создается при каждой проверке mod, то есть при каждом проходе цикла (раз в несколько миллисекунд) случайное значение будет меняться. Я бы вообще использовал одну переменную вместо двух, да вы видели. Но если хотите две ошибкой это не будет, только объявлять и менять их надо правильно. Кстати, присваивать случайное значение стоит по нажатию кнопки а не по проверке режима.
asm ("sei"); - достаточно впихнуть в main?
Лучше использовать именно макрос sei() а не ассемблерную вставку, это считается более безопасным способом. Вставить лучше всего прямо перед бесконечным циклом, когда переферия уже настроена.
Встал на лапы
Сообщения: 131
Зарегистрирован: Вс май 08, 2016 22:45:48

Сообщение sTRog »

И вот я прошил МК.

Но почему то, вместо того, чтобы светодиот зажигался на 1 и 3 сек соотвественно, он горит постоянно. В чем может быть проблема
а) На програмном уровне?
б) Ну и возможно на самой схеме, хотя прозвонил все - нигде перемычек не нашел, вот.
Ответить

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