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

Вопросы от начинающих по МК


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

void voltage(void)//здесь получим значение напряжения
{
    ADMUX|=(1<<MUX2)|(1<<MUX0);ADMUX&=~((1<<MUX1)|(1<<MUX3));//ADC5
	ADCSRA|=(1 << ADSC); // запуск преобразования
		static unsigned int ADC_value;//переменная суммы измерений
		static unsigned char count;//переменная суммы количества измерений
		ADC_value+=ADC;//складываем ADC 64раза
		if (count==64)//если прошло 64 измерения
		{
			ADC_value>>=6;//расчитываем среднее значение побитовым сдвигом
			value=(ADC_value*500L)>>10;//получаем значение напряжения при он 5,00 вольт L-означает
			//что хотим получить в 32 битах, >>10 сдвинув на 10 получим 16бит
			ADC_value=0;
			count=0;
		}
		else
		{
			count++;//делаем следующий замер
		}
}
int main(void)
{
	port_ini();
	lcd_ini();
	ADC_ini();
	int value;
	while (1)
	{
		lcd_poz(0);
		//lcd_string("I love Maria");
		value=voltage();//запишем значение напряжения в переменную
		lcd_num_to_str(value);//выводим ее на экран
		
	}
}

а так?

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

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

  • Ответов
  • Создана
  • Последний ответ

Топ авторов темы

@Дмитрий Мамедиев , функция должна реализовывать своё основное назначение: получать параметр и возвращать значение. Это как комната с двумя окошками: в одно вы даете бумажку с заданием, а из другого получаете результат исполнения этого задания. Что это такое:

void current(void)
void voltage(void)

Это две комнаты, причем ни задания находящиеся там люди не получают, и результат выдают не тому, кто попросил, а кидают куда-то в окно - подбирайте, люди добрые, кто хочет или не хочет... А по смыслу это одно и то же! Комната "измерение", в окошко подаем задание "ток" или "напряжение", на выходе получаем значение...

int get_adc_value(int chanel);

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

Такой подход ни противоречит здравому смыслу, лаконичен (без повторов кода), удобен и соответствует духу языка Си.

Почему вы упорно игнорируете советы по "методу написания кода", сразу приступая к кодописанию? Получается же ерунда!

Кстати, вам тут советуют проводить усреднение какое-то... Это все верно, но, во-первых, это надо делать не одновременно с измерением, а после того, как вы сможете, наконец, получать нужные значения из АЦП без проблем. Во-вторых, фильтр так же должен быть "комнатой" - на входе очередное значение из АЦП, а на выходе - отфильтрованное.

int current_filtr(int val); // фильтр тока
int voltage_filtr(int val); // фильтр напряжения

current = current_filtr(get_adc_val(CURRENT_INPUT));
voltage = voltage_filtr(get_adc_val(VOLTAGE_INPUT));

 

Абстрагируйтесь от битов и пинов, сначала опишите суть абстрактными выражениями, каждое из которых затем так же рекурсивно разбивайте на более мелкие абстракции, их - снова и снова, пока не останутся "атомы", которые уже не требуют детализации - и так все конкретно. Понимаете, о чем я?

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

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

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

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

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

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

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

3 часа назад, Дмитрий Мамедиев сказал:

а так?

не, вот так:

Скрытый текст

#define CHANNEL_VOLT 0
#define CHANNEL_CURENT 1
unsigned char buffer_volt[5]={'0',',','0','0',0};
unsigned char buffer_curent[5]={'0',',','0','0',0};

void ADC_ini(void)
{
 ADCSRA =(1<<ADEN) // включаем ацп
	    |(0<<ADSC) // запуск преобразования/не запускаем
	    |(0<<ADFR) // круговой режим отключен
	    |(0<<ADIF) // очищаем флаг окончания преобразования АЦП
	    |(0<<ADIE) // запрет прерывания от АЦП (не используем)
	    |(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//делитель на 128
	    
 ADMUX = (0<<REFS1)|(1<<REFS0)// Vref=AVcc
        |(0<<ADLAR) // правое выравнивание результата АЦП
        |(0<<MUX3)|(0<<MUX0)|(0<<MUX0)|(0<<MUX0);// включен канал ADC0
	
}

unsigned int read_ADC (char channel)
{
 ADMUX &= 0xF8;
 ADMUX |= channel&0x07; //выбираем канал
 _delay_us(50);
  ADCSRA |= (1<<ADSC) // запуск преобразования
  while(ADCSRA&(1<<ADSC)) continue; // ждем окончание преобразования АЦП
// если не будет автоматического сброса при одиночном преобразовании
// заменить на :
//  while(0==(ADCSRA&(1<<ADIF)) continue; // ждем окончание преобразования АЦП
//  ADCSRA&=~(1<<ADIF); //  очищаем флаг окончания преобразования АЦП
//  ADCSRA &=~(1<<ADSC)
  asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации 
  asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации 
  return  (ADCL|ADCH<<8);
} 
void convert_ADC_volt(void)
{
	unsigned int value;//значение измеренной величины
	static unsigned int ADC_value;//переменная суммы измерений
	static unsigned char count;//переменная суммы количества измерений
	ADC_value+=read_ADC(CHANNEL_VOLT);//складываем ADCW 64раза
	if (count==64)//если прошло 64 измерения
	{
		
		ADC_value>>=6;//расчитываем среднее значение побитовым сдвигом
		value=(ADC_value*500L)>>10;//получаем значение напряжения при он 5,00 вольт L-означает
		//что хотим получить в 32 битах, >>10 сдвинув на 10 получим 16бит
		//делим число и выводим посимвольно в buffer, buffer[1] значение запятой
		buffer_volt[0]=(value/100)+'0';
		buffer_volt[2]=((value%100)/10)+'0';
		buffer_volt[3]=(value%10)+'0';
		ADC_value=0;
		count=0;
	}
	else
	{
		count++;//делаем следующий замер
	}
}
void convert_ADC_curent(void)
{
    unsigned int value;//значение измеренной величины
	static unsigned int ADC_value;//переменная суммы измерений
	static unsigned char count;//переменная суммы количества измерений
	ADC_value+=read_ADC(CHANNEL_CURENT);//складываем  64раза
	if (count==64)//если прошло 64 измерения
	{
		
		ADC_value>>=6;//расчитываем среднее значение побитовым сдвигом
		value=(ADC_value*500L)>>10;//получаем значение напряжения при он 5,00 вольт L-означает
		//что хотим получить в 32 битах, >>10 сдвинув на 10 получим 16бит
		//делим число и выводим посимвольно в buffer, buffer[1] значение запятой
		buffer_curent[0]=(value/100)+'0';
		buffer_curent[2]=((value%100)/10)+'0';
		buffer_curent[3]=(value%10)+'0';
		ADC_value=0;
		count=0;
	}
	else
	{
		count++;//делаем следующий замер
	}
}

int main(void)
{
	port_ini();
	lcd_ini();
	ADC_ini();
	
	while (1)
	{
      convert_ADC_volt();
      convert_ADC_curent();
      
      lcd_poz(0);
	  lcd_string(buffer_volt);
      
      lcd_poz(8);
	  lcd_string(buffer_curent);
      
	}
}

 

фунции лсд и настройки портов добавите сами.

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

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

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

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

Сравнительное тестирование аккумуляторов EVE Energy и Samsung типоразмера 18650

Инженеры КОМПЭЛ провели сравнительное тестирование аккумуляторов EVE и Samsung популярного для бытовых и индустриальных применений типоразмера 18650. 

Для теста были выбраны аккумуляторы литий-никельмарганцевой системы: по два образца одного наименования каждого производителя – и протестированы на двух значениях тока разряда: 0,5 А и 2,5 А. Испытания проводились в нормальных условиях на электронной нагрузке EBD-USB от ZKEtech, а зарядка осуществлялась от лабораторного источника питания в режиме CC+CV в соответствии с рекомендациями в даташите на определенную модель. Подробнее>>

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

1 час назад, Дмитрий Мамедиев сказал:

видимо это не мое

Для того, чтобы стало интересно заниматься ЛЮБЫМ делом, нужно преодолеть скучный и трудоемкий барьер ВХОДА в это дело. Иначе Вы никогда ничему не научитесь. Будете только мелочь по карманам тырить...

 

戦う前に相手のベルトの色に注目

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

Литиевые аккумуляторы EVE Energy и решения для управления перезаряжаемыми источниками тока (материалы вебинара)

Опубликованы материалы вебинара Компэл, посвященного литиевым аккумуляторам EVE Energy и решениям для управления перезаряжаемыми источниками тока.

На вебинаре мы представили информацию не только по линейкам аккумуляторной продукции EVE, но и по решениям для управления ею, что поможет рассмотреть эти ХИТ в качестве дополнительной альтернативы для уже выпускающихся изделий. Также рассмотрели нюансы работы с производителем и сервисы, предоставляемые Компэл по данной продукции. Подробнее>>

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

Литиевые батарейки и аккумуляторы от мирового лидера  EVE в Компэл

Компания Компэл, официальный дистрибьютор EVE Energy, бренда №1 по производству химических источников тока (ХИТ) в мире, предлагает продукцию EVE как со склада, так и под заказ. Компания EVE широко известна в странах Европы, Америки и Юго-Восточной Азии уже более 20 лет. Недавно EVE была объявлена поставщиком новых аккумуляторных элементов круглого формата для электрических моделей «нового класса» компании BMW.

Продукция EVE предназначена для самого широкого спектра применений – от бытового до промышленного. Подробнее>>

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

#define current (0<<MUX0)|(0<<MUX1)|(1<<MUX2)|(0<<MUX3)
int ADC_convert (unsigned char chanel)
{
	chanel=ADMUX
и т.д.

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

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

Ещё раз, Дмитрий: сначала рисуете крупными мазками наиболее общее, затем проводите постепенные уточнения. Не спешите сразу сделать все.

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

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

показал четыре нуля, уже достижение

я думаю здесь проблема

#define current (0<<MUX0)|(0<<MUX1)|(1<<MUX2)|(0<<MUX3)//ADC4
#define voltage (1<<MUX0)|(0<<MUX1)|(1<<MUX2)|(0<<MUX3)//ADC5

 

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

Это называется метод чёрного ящика.

А вообще, вам бы сначала алгоритм нарисовать, а потом кодировать. Если сложности с рисованием алгоритма, значит требования не проработаны до конца и не всё формализовано.

Вот эти вот все прямоугольнички, ромбики, ...

Учение - изучение правил. Опыт - изучение исключений.

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

Я понимаю что нужен алгоритм, пытаюсь, просто не хватает знаний. Например усреднение через битовый сдвиг...., да я бы в жизнь до этого не догадался.

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

Только что, Дмитрий Мамедиев сказал:

да я бы в жизнь до этого не догадался

Я вам постоянно повторяю: не хватайтесь за все сразу. Слона надо есть маленькими кусочками. Какой ещё битовый сдвиг?! Формула усреднения вам из курса школькой арифметики знакома? Вот её и надо делать на первых порах. А до тех пор, пока вы с нею не определились, используйте метод, о котором я вам все время твержу: все, что пока не понятно, как работает, но есть уверенность, что оно нужно, заменяем функцией-пустышкой, и далее считаем, что она делает именно то, что надо. Когда все остальное заработает, тогда возвращаемся к этой функции и напоняем её смыслом.

Все это к тому, что в вашем коде на каждом этапе разработки должна быть только одна функция (одно место), которое требует отладки, т.е. в работе которого у вас нет уверенности. Если таких мест два или больше - сливай воду, туши свет.

Вот пример: я вам ранее писал, что данные надо фильтровать и для этого придумал функцию фильтра - я приводил код этой функции? Нет. Т.е. её (точнее их, т.к. у вас ток и напряжение могут фильтроваться по-разному) надо заменить на вот такое:

int current_filtr(int value){
	return value;
}

int voltage_filtr(int value){
	return value;
}

При этом все прочие участки кода будут уверены, что фильтры у вас есть, но вы сами ни сном ни духом не знаете, как их сделать... Когда вы отладите измерение через АЦП, индикацию, вы вспомните про фильтры... А до тех пор вы должны только знать, что они есть (будут). Если у вас не работает индикация - поступаете точно так же (хотя лучше начать именно с нее, иначе как узнавать о том, что что-то заработало?). Или наоборот, не получается АЦП - вставляете заглушку типа

int get_adc_value(char chanel){
	return rand() % 1024; // случайное число от 0 до 1023
	// или можно конкретное число - для отладки индикации бывает полезнее
	// return 270;
}

И возитесь с индикацией.

Понимаете идею?

На каждом этапе только одно место в коде должно вызывать вопросы - только одно! Если вопросов больше - все, кроме одного, заменяем "заглушками" и работаем только с выбранным. Добились правильной его работы - поочередно занимаемся заглушенными функциями. По одной за раз. И так далее.

Кстати, фильтр может быть таким (после того, как со всем прочим разберетесь, помозгуйте на досуге, как и что он делает):

#define AVERAGE		16

int filtr(int value){
	static int val[AVERAGE];
	static int cur;
	long sum = 0;

	val[cur] = value;
	if(++cur >= AVERAGE) cur = 0;

	for(int i=0; i < AVERAGE; i++)
		sum += val[i];
                             
	return sum / AVERAGE;
}

 

Кстати, алгоритм, который вам тут советовали рисовать квадратиками-стрелочками, можно сразу писать на Си при помощи рекомендуемых мной функций-ЗАГЛУШЕК, ибо квадратик со стрелочками ничем не лучше функции пустышки. Иногда можно даже просто писать текстом в виде комментариев, а затем под комментарии дописывать операторы Си...

А потом, как уже было сказано, пустышки наполняются смыслом... И алгоритм автоматически превращается в программу.

Изменено пользователем ARV

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

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

Помогите понять, строки из даташита: если какие либо разьемы ацп (3...0) используются в качестве цифровых выходов, важно, чтобы они не переключались во время выполнения преобразования. Однако, используя 2- проводной интерфейс (ацп4 и ацп5) будет влиять только на преобразование на ацп4 и ацп5, а не на другие.

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

Будет влиять на другие. Дело в том что AVCC и AGND выводы это выводы питания порта PC, на котором сидит и АЦП, поэтому ток по любому из выводов этих портов будет протекать по аналоговым шинам питания и неизбежно ВЛИЯТЬ на потенциал AGND что будет влиять на результат измерения по остальным выводам. А если в качестве опорного используется напряжение питания, то влиять будет так же и потенциал AVCC.

Учение - изучение правил. Опыт - изучение исключений.

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

Из даташита на ATmega88

Цитата

PC5 can also be used as ADC input Channel 5. Note that ADC input channel 5 uses digital power.

PC4 can also be used as ADC input Channel 4. Note that ADC input channel 4 uses digital power.

То есть PC0-PC3, PC6 питаются от аналогового питания, а PC4, PC5 от цифрового.

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

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

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

В 22.03.2019 в 00:53, Alexeyslav сказал:

Будет влиять на другие. Дело в том что AVCC и AGND выводы это выводы питания порта PC, на котором сидит и АЦП, поэтому ток по любому из выводов этих портов будет протекать по аналоговым шинам питания и неизбежно ВЛИЯТЬ на потенциал AGND что будет влиять на результат измерения по остальным выводам. А если в качестве опорного используется напряжение питания, то влиять будет так же и потенциал AVCC.

Тут важно как сигнал присоединен к АЦП. Сам по себе потенциал аналоговой земли на КОНТРОЛЛЕРЕ не имеет никакого значения. Если общий провод сигнала от аналогового источника подключен прямо к пину аналоговой земли МК с плавающим потенциалом, то весь аналоговый сигнал будет плавать вместе с этой землей и помеха станет синфазной. Останется лишь очень короткий участок самого вывода микросхемы. Но для 10-разрядного АЦП это совершенно не принципиально. По любому, младший разряд будет гладким лишь если имеет место быть усреднение.

戦う前に相手のベルトの色に注目

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

@my504 хотите сказать что при проектировании нужно земли разделить? усреднение будет.

unsigned int ADC_convert (char chanel)
{
	ADMUX|=chanel&0x0F;//выбираем канал 
	ADCSRA|=(1<<ADSC); // запуск преобразования
	 while(0==(ADCSRA&(1<<ADIF))) continue; // ждем окончание преобразования АЦП
	 ADCSRA&=~(1<<ADSC); //выключаем преобразование
	 asm("nop"); //Небольшая задержка в 1 такт МК, для стабилизации
	static unsigned int ADC_value;//переменная суммы измерений
	static unsigned char count;//переменная суммы количества измерений
	ADC_value+=(ADCL|ADCH<<8);//складываем результат измерения 64 раза
	if (count==64)//если прошло 64 измерения
	{
		ADC_value>>=6;//расчитываем среднее значение побитовым сдвигом
		value=(ADC_value*500L)>>10;//получаем значение напряжения при он 5,00 вольт L-
		//означает что хотим получить в 32 битах, >>10 сдвинув на 10 получим 16бит
		ADC_value=0;
		count=0;
	}
	else
	{
		count++;//делаем следующий замер
	}
    return value;
}
	while (1)
	{
		lcd_poz(0);
		lcd_num_to_str(ADC_convert(5));
		lcd_poz(8);
		lcd_num_to_str(ADC_convert(4));		
	}

сделал так, но в двух позициях отображается только сигнал на 5 канале. обнуление канала ничего не дает. где косяк? 

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

Между запуском и переключением канала должна быть задержка согласно даташиту. Это если эквизишн тайм (окно захвата) не входит в цикл преобразования, то есть старт преобразования немедленно отключает УВХ от входа.

戦う前に相手のベルトの色に注目

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

2 часа назад, Дмитрий Мамедиев сказал:

где косяк? 

 действительно полагаешь, что суммируя значения разных каналов АЦП в одну переменную на выходе возвращается  средние для каждого  канала отдельно???  о том что из примера повыкидывал критические команды чтения АЦП в принципе уже можно не  говорить.

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

5 часов назад, IMXO сказал:

действительно полагаешь, что суммируя значения разных каналов АЦП в одну переменную на выходе возвращается  средние для каждого  канала отдельно???

А ведь не один раз я писал и объяснял, что фильтрация должна быть отдельно от семплирования... Получение среднего - тоже фильтр. 

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

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

не понимаю ваши возмущения, ТС принял вашу политику раздельных кубиков и делает согласно своему разумению , предложенная вами функция int filtr(int value) не чем не лучше функции ТС , вызовете ее для разных каналов АЦП и получите те же грабли .

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

47 минут назад, IMXO сказал:

предложенная вами функция int filtr(int value) не чем не лучше функции ТС , вызовете ее для разных каналов АЦП и получите те же грабли .

А если вилку в розетку совать, то можно электротравму получить. Но ведь это не означает, что вилка - плохой инструмент?

Топикстартера я пытался вразумить, как следует подходить к решению проблем вообще, т.е. не алгоритм решения его конкретной задачи, а алгоритм решения любой задачи. Учиться же можно только на простых примерах, и вы оказали ТС-у медвежью услугу, огорошив его необходимостью фильтрации в то время, как он еще и с семплированием не разобрался. Я пытался эту ситуацию исправить, выделив фильтр в отдельное место и позволив ему хоть понемногу разгрести завалы... Про фильтр следовало бы упоминать только после того, как ТС сделал бы свой вольтметр и убедился, что показания пляшут, тогда он осознал бы необходимость, и был бы вынужден ВСТРАИВАТЬ новую функцию в готовый и работающий код, что позволило бы ему на практике понять, что такое модульность и какие преимущества она дает...

А теперь... даже и не знаю, чем помочь.

 

P.S. Кстати, справедливости ради: я рекомендовал ему иметь две разные функции с разными фильтрами. 

Изменено пользователем ARV

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

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

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

Но ведь это не означает, что вилка - плохой инструмент?

конечно нет, просто суп ей есть не очень удобно. 

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

Про фильтр следовало бы упоминать только после

:)  перечитайте тему внимательно с 286стр.  я лишь привел один из примеров его реализации. 

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

Доброго всем времени суток! Прошу помочь мне с решением моей проблемы. Итак... решил я "причесать" свой код обычного таймера. Создал, как положено 2 файла add.h и add.c, в add.h прототипы функций, в add.c их реализация. С функцией, которая не использует глобальных переменный проблем не возникло. Проблемы начались, когда я захотел перенести  в add.h и add.c функцию использующую глобальные переменные. Сразу вывалилась куча ошибок, понял, что необходимо использовать спецификатор extern, ошибок стало меньше, но они всё равно остались.:(  Вот сам лог. 

1.jpg.6c0d8ac1c6c8f3272f637bf9b8168f2a.jpg

Вот код main.cpp

#include "add.h"
#include "add.c"

volatile uint16_t bcount = 0; // счетчик для подавления дребезга
volatile uint16_t count = 0;

#define ON(n) PORTC |=_BV(n)
#define OFF(n) PORTC &=~_BV(n)

bool Timer_status = 0; // статус таймера

uint8_t NUM[12] = {0b00111111 ,0b00000110, 0b01011011, 0b01001111, 0b01100110, 0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111, 0b00111001, 0b01100011};  // 9 0b01101111

extern uint8_t N1, N2, N3, N4 = 0;

uint8_t Timer_count = 0; // число для отсчёта таймером



void read_encoder() {
	
	static uint8_t a=0;
	if (!a)
	{
		if ((bit_is_clear(PINC,5))||(bit_is_clear(PINC,4)))
		{
			a=1;
			if (bit_is_clear(PINC,5)) if (Timer_count<255) Timer_count++;
			if (bit_is_clear(PINC,4)) if (Timer_count>0) Timer_count--;
		}
	}
	
	if ((bit_is_set(PINC,5))&&(bit_is_set(PINC,4) )) a = 0;

}




uint8_t Button_state() {
	
	static uint16_t smillis = 0;
	static bool flag = 0;
	static bool flag2 = 0;
	uint8_t stat = 0;
	
	
	if(bit_is_clear(PINB,0))
	{
		if(!flag2) {cli(); bcount=0; sei(); flag2=1;}
		if(!smillis) smillis = bcount;
		if(!flag && bcount-smillis > 500)
		{
			stat = !stat;
			flag = 1;
			Timer_status = !Timer_status;
		}
	}
	
	if(smillis && !(bit_is_clear(PINB,0)))
	{
		if(bcount-smillis <= 500 && bcount-smillis > 30) {}
		smillis = 0;
		flag = 0;
	}
	
	return stat;
	stat = 0;
	flag2 = 0;
}

ISR(TIMER2_OVF_vect) {

	if( Timer_status && Timer_count != 0) {
		Timer_count--;
		//PORTB ^=_BV(2);
	}
	
	if(Timer_count==0 && Timer_status) {
		Timer_status = 0;
		PORTB ^=_BV(1);
	}
}

ISR (TIMER0_OVF_vect)
{
	bcount++;
	static uint8_t i=0;
	i=++i%5;
	if(i==0) { OFF(3); PORTD = NUM[N1]; ON(0); }
	if(i==1) { OFF(0); PORTD = NUM[N2]; ON(1); PORTD |=_BV(7); }
	if(i==2) { OFF(1); PORTD = NUM[N3]; ON(2); }
	if(i==3) { OFF(2); PORTD = NUM[N4]; ON(3); }
	
}


int main(void)
{
	DDRD = 255;
	PORTD = 0; // разряды
	
	DDRC = 0b00001111;
	PORTC = 0; // сегменты, + - энкодера
	
	DDRB |=(1<<2) | (1<<1); // светодиоды, кнопка энкодера
	PORTB = 0b00000110;
	
	cli();
	TIMSK |= (1 << TOIE0);
	TCCR0 |= (1<<CS01) | (1<<CS00);
	TCCR0 &= ~((1<<CS02)); // | (1<<CS00)); // без предделителя
	TCNT0 = 0;
	
	ADMUX |= ( _BV(REFS1) | _BV(REFS0) | _BV(MUX2) );  // | _BV(ADLAR)); // опрное напряжение 2.56В, ADC4
	ADCSRA |= ( _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0) ); // разрешаем работу АЦП, предделитель 8
	
	
	ASSR |= (1 << AS2); // Включаем асинхронный режим T2
	TCNT2 = 0; // Сбрасываем регистр счета
	while(ASSR != (0b00001000)) asm ("nop"); // дожидаемся разрешения на запись
	TCCR2 = 0b00000101; // Предделитель на 128
	TIMSK |= (1 << TOIE2); // Разрешаем прерывание по переполнению
	TIFR = 0;

	sei();
	
	
	while (1)
	{
		
		Button_state();
		readADC();
		separation(Timer_count);
    }
}

add.c 

#include "add.h"

uint8_t N1, N2, N3, N4;

int32_t readADC(){
	
	int32_t value = 0;
	for(uint8_t k=0;k<255;k++)
	{
		for (uint16_t b = 0;b<10000;b++){asm("nop");}
		ADCSRA |= 1<<ADSC;
		while(ADCSRA&(1<<ADSC));
		value += ADC;
	}
	
	return ((value >> 8) >> 2) + 2;
}


void separation(int num) {
	
	cli();
	N1=0; N2=0; N3=0; N4=0;
	N1 = num/1000;
	N2 = (num%1000)/100;
	N3 = (num%100)/10;
	N4 = num%10;
	sei();

}

Ну и add.h

#ifndef ADD_H_
#define ADD_H_

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


int32_t readADC();
void separation(int num);

#endif /* ADD_H_ */

Никак не пойму, что не так с переменными N1, N2, N3, N4 и почему ошибки касаются только N4???, а не всех остальных. Люди добрые подскажите как быть и, что с этим безобразием делать....

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

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

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

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

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

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

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

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

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

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

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

×
×
  • Создать...