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

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


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

10 часов назад, ARV сказал:

А как же integer promotions:shok:

Размер integer стандартом не определен. Собственно, именно поэтому ввели всякие int32_t.

Более того, размер integer в препроцессоре не связан с integer языка Си и равен как раз 32 битам. Не уверен насколько оно стандартизовано, но вот в моей версии препроцессора так.

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

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

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

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

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

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

Размер integer стандартом не определен.

И для рассматриваемого avr-gcc определено sizeof(int) == 2

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

размер integer в препроцессоре не связан с integer языка Си и равен как раз 32 битам

А вот тут у меня другие сведения: только для gnu-as при вычислениях на этапе компиляции используется размер int хост-платформы, а для самого компилятора Си вроде как используется именно размерность int целевой платформы. Во всяком случае я читал именно такое...

42 минуты назад, Дмитрий Мамедиев сказал:

А как мне правильно написать в таком случае?

Вам же писали ранее - суффикс L решает проблему вычислений. 1024*512L всегда будет однозначно правильно.

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

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

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

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

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

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

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

Вам же писали ранее - суффикс L решает проблему вычислений. 1024*512L всегда будет однозначно правильно.

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

//задаем канал и получаем значение ацп
unsigned int ADC_read(unsigned char chanel)
{
	ADMUX&=0xF0;//обязательно обнуляем канал
	ADMUX|= chanel&0x0F;//задаем канал
	ADCSRA |= (1<<ADSC); // запуск преобразования
	while(0==(ADCSRA&(1<<ADIF))) continue;// ждем окончание преобразования АЦП
	//когда преобразование завершено ADIF устанавливается в 1 и мы его сбрасываем в 0
	ADCSRA&=~(1<<ADIF); //  очищаем флаг окончания преобразования АЦП
	ADCSRA &=~ (1<<ADSC);//выключаем преобразование
	return ADCW;
}
//вычисляем значение напряжения
unsigned char ADC_voltage(unsigned int value)
{
	static unsigned int ADC_value;//переменная суммы измерений
	static unsigned char count;//переменная суммы количества измерений
	ADC_value+=value;//складываем ADCW 64раза
	if (count==64)//если прошло 64 измерения
	{
		ADC_value>>=6;//расчитываем среднее значение побитовым сдвигом
		volt=(1024*500L)>>10;//500 это 50,0 т.е. предел измерения. L-означает
		//что хотим получить в 32 битах, >>10 сдвинув на 10 получим 16бит
		count=0;
		ADC_value=0;
	}
	else
	{
		count++;
	}
	return volt;
}

а вот так я их вывожу

//функция вывода чисел
void lcd_chisla(unsigned int chislo)
{//делим число и выводим посимвольно в buffer, buffer[2] значение запятой
	unsigned char buffer[5]={'0','0',',','0',0};
	buffer[0]=(chislo/100)+'0';
	buffer[1]=((chislo%100)/10)+'0';
	buffer[3]=(chislo%10)+'0';
	for (unsigned char i=0;i<5;i++)
	{
		lcd_data(buffer[i]);
	}
}
lcd_poz(0);
		lcd_chisla(ADC_voltage(ADC_read(5)));

так вот отладчиком шагая volt=((1024*500L)>>10)=500 тут получаем правильно но вот chislo уже 244 становится.

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

Новый аккумулятор EVE серии PLM для GSM-трекеров, работающих в жёстких условиях (до -40°С)

Компания EVE выпустила новый аккумулятор серии PLM, сочетающий в себе высокую безопасность, длительный срок службы, широкий температурный диапазон и высокую токоотдачу даже при отрицательной температуре. 

Эти аккумуляторы поддерживают заряд при температуре от -40/-20°С (сниженным значением тока), безопасны (не воспламеняются и не взрываются) при механическом повреждении (протыкание и сдавливание), устойчивы к вибрации. Они могут применяться как для автотранспорта (трекеры, маячки, сигнализация), так и для промышленных устройств мониторинга, IoT-устройств. Подробнее параметры и результаты тестов новой серии PLM по ссылке.

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

3 часа назад, ARV сказал:

А вот тут у меня другие сведения: только для gnu-as при вычислениях на этапе компиляции используется размер int хост-платформы, а для самого компилятора Си вроде как используется именно размерность int целевой платформы. Во всяком случае я читал именно такое...

Какое дело препроцессору до хоста или целевой платформы?

Тут может быть другое - препроцессор старается сделать все в текстовом виде, ничего не вычисляя. В случае сравнений ему, понятное дело, выбора не оставляют, но обычные выражения он может отдать на откуп компилятору, и там уж как тот решит.

В любом случае у меня с int-long проблем не было ни разу, даже если объявлять F_CPU без модификаторов, все макросы и расчеты работают нормально. С другой стороны, написать одну-две буквы тоже не запредельный труд, а хуже от этого не будет.

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

ADCSRA&=~(1<<ADIF); // очищаем флаг окончания преобразования АЦП

ADCSRA &=~ (1<<ADSC);//выключаем преобразование

Вроде как флаги прерываний сбрасываются записью лог.1. А сбрасывать ADSC вообще не нужно, оно сбросится само.

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

volt=(1024*500L)>>10;//500 это 50,0 т.е. предел измерения. L-означает

Вас не смущает, что это присвоение константы?

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

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

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

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

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

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

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

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

Вроде как флаги прерываний сбрасываются записью лог.1. А сбрасывать ADSC вообще не нужно, оно сбросится само

как я понял по окончании преобразования флаг устанавливается в 1, поэтому сбрасываем его в 0.

 

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

Вас не смущает, что это присвоение константы?

1024 заменяется на результат с ацп, здесь я поставил 1024 чтобы увидеть результат в отладчике 

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

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

ну в общем я опять в тупике

ну шо просил, то и получил....  :unknw:

unsigned char ADC_voltage(unsigned int value)

(int)volt = 500 = 111110100  >=> (char)  x11110100 = 244 

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

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

как я понял по окончании преобразования флаг устанавливается в 1, поэтому сбрасываем его в 0.

О чем и речь. Сброс в 0 осуществляется не записью 0, а записью 1.

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

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

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

По окончании преобразования сам падает флаг ADSC, проще ждать его обнуления. И действий меньше, а флаг прерывания оставить для использования по прямому назначению.

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

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

ну наконец-то... осталось доработать напильником.... заменив

ADC_value>>=6;//расчитываем среднее значение побитовым сдвигом
value=(ADC_value*500L)>>10;//получаем значение напряжения при он 5,00 вольт L-означает
		//что хотим получить в 32 битах, >>10 сдвинув на 10 получим 16бит

на лаконичное 

value=(ADC_value*500L)>>16;//расчитываем среднее значение побитовым сдвигом >>6
                           //получаем значение напряжения при он 5,00 вольт L-означает
		                   //что хотим получить в 32 битах, >>10 сдвинув на 10 получим 16бит

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

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

Всех приветствую! Появилось немного времени поработать над кодом таймера.:) Вот код в мейне

#include "add.h"

uint8_t NUM[12] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111, 57, 99};  // 9 0b01101111
//                 0   1  2   3    4    5    6   7   8    9   C   о

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

uint16_t Timer_count = 0; // число для отсчёта таймером
bool Timer_status = 0; // статус таймера
volatile bool Timer_finished = 0; // завешение раблты таймера

bool Long_press = 0; // длительное нажаие кнопки
bool Short_press = 0; // корткое нажаие кнопки


void Button_state();


uint8_t read_encoder() {
	
	static bool a=0;
	uint8_t b=0;
	if (!a)
	{
		if (Up0||Down0)
		{
			a=1;
			if (Up0) {
				if(!Timer_status) if (Timer_count<9999) Timer_count++;
				}
			
			if (Down0) {
				if(!Timer_status) if (Timer_count>0) Timer_count--;
			}
		}
	}
	
	if (Up1&&Down1) a = 0;
	return b;
	
}


void Button_state() {
	
	static uint16_t smillis = 0;
	static uint8_t flag = 0;
	static uint8_t flag2 = 0;
	
	if(bit_is_clear(PINB,0))
	{
		if(!flag2) {cli(); bcount=0; sei(); flag2=1;}
		if(!smillis) smillis = bcount;
		if(!flag && bcount-smillis > 500)
		{
			flag = 1;
			PORTB ^=_BV(1);
		}
	}
	
	if(smillis && !(bit_is_clear(PINB,0)))
	{
		if(bcount-smillis <= 500 && bcount-smillis > 20) PORTB ^=_BV(2);;
		smillis = 0;
		flag = 0;
	}
	
	return 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_finished = 1;
		if(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); }
	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 = 0b00000000;
	
	cli();
	TIMSK |= (1 << TOIE0);
	TCCR0 |= (1<<CS01) | (1<<CS00);
	TCCR0 &= ~((1<<CS02)); // | (1<<CS00)); // без предделителя
	TCNT0 = 0;
	
	
	ASSR |= (1 << AS2); // Включаем асинхронный режим T2
	TCNT2 = 0; // Сбрасываем регистр счета
	while(ASSR != (0b00001000)) asm ("nop"); // дожидаемся разрешения на запись
	TCCR2 = 0b00000101; // Предделитель на 128
	TIMSK |= (1 << TOIE2); // Разрешаем прерывание по переполнению
	TIFR = 0;
	
	sei();
	
	
	while (1)
	{
		

		read_encoder();
		Button_state();
		separation(Timer_count);
		//if(Long_press) PORTB ^=_BV(1);
		//if(Short_press) PORTB ^=_BV(2);
}
}

Загвоздка вот в чем... Имеется функция Button_state, которая считывает длительное и короткое нажатие кнопки. Внутри функции все работает как положено. Но... мне хотелось прописать основную логику не в самой функции Button_state, а в основном цикле while. Недолго думая, создал 2 глобальные переменные Long_press и Short_press, в функции я просто присваиваю им 1 если выполнилось нужное действие. Вот так это безобразие выглядит...

void Button_state() {
	
	static uint16_t smillis = 0;
	static uint8_t flag = 0;
	static uint8_t flag2 = 0;
	
	if(bit_is_clear(PINB,0))
	{
		if(!flag2) {cli(); bcount=0; sei(); flag2=1;}
		if(!smillis) smillis = bcount;
		if(!flag && bcount-smillis > 500)
		{
			flag = 1;
			//PORTB ^=_BV(1);
			Long_press = 1;
		}
		else Long_press = 0;
	}
	
	if(smillis && !(bit_is_clear(PINB,0)))
	{
		if(bcount-smillis <= 500 && bcount-smillis > 20) Short_press = 1;//PORTB ^=_BV(2);
		else Short_press = 0;
		smillis = 0;
		flag = 0;
	}
	
	return 0;
	flag2 = 0;
}

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

if(Long_press) PORTB ^=_BV(1);
if(Short_press) PORTB ^=_BV(2);

Ничего не получается индикатор мерцает(работу симулирую  в протеусе) Светодиоды то включатся, то не включатся, короче херня полная. Ну ладно подумал я и решил попробовать передать в качестве аргументов в функцию адреса переменных Long_press и Short_press с помощью указателей, внутри функции с указателями работал точно по такому же принципу как и с глобальными переменными. Но, увы и при таком подходе результат я получил похожий на первый((( Подскажите люди добрые, что я делаю не так??????????

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

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

Ничего не получается

а что вы хотите получить в итоге работы этого мозгодробильного кода?  минут 15 пытался вникнуть, но так и них не понял. складывается мнение о удалении гланд через анус.

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

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

а что вы хотите получить в итоге работы этого мозгодробильного кода?  минут 15 пытался вникнуть, но так и них не понял. складывается мнение о удалении гланд через анус.

Нуу... Пишу как умею) Просто не весь функционал ещё реализован. Проблема в том, что я не могу вернуть из функции 2 значения, ни через глабальные переменные, ни через указатели, переданные в функцию в качестве аргументов, точнее они возвращаются, но работает это все некорректно. Что касается кода, тут всё , как я считаю, довольно просто. В функции  read_encoder происходит считывание энкодера, соответственно прибавляется или уменьшается переменная Timer_count. Далее если нажать кнопку энкодера, значение которой считываеся функцией Button_state, значение переменной Timer_status меняется на противоположное(эта строчка не прописана в коде) и в обработчик прерываний 2 таймера начинается обратный отчёт. По завершении отчёта, также о обработчике инвертировалось значение светодиода, просто как индикация срабатывания таймера. 

 

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

Как часто срабатывают прерывания таймеров?

Дело в том, что если опрашивать состояние кнопок с периодом не менее 10 мс (вполне оптимально 20-50 мс), никакого подавления дребезга дополнительно не потребуется. Это и к энкодерам относится. Соответственно, вся логика сильно упрощается.

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

я не могу вернуть из функции 2 значения

А вот это странно.

#define BTN_LONG	1
#define BTN_SHORT	2
#define BTN_NONE	0
  
uint8_t button_state(void){
   if(..что-то-там..)
     return BTN_SHORT;
   else if(..еще-что-то-там..)
     return BTN_LONG;
   else
    return BTN_NONE;
}

Так не можете сделать, что ли?

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

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

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

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

Это и к энкодерам относится

Я подавляю дребезг только кнопки энкодера и одновременно реализуется отслеживание длительного и короткого её нажатия.

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

Как часто срабатывают прерывания таймеров?

0 таймер работает с частотой 125000 Гц, а 2 работает в асинхронном режиме от внешнего часового кварца.

3 часа назад, ARV сказал:

Так не можете сделать, что ли?

Попробовал 

uint8_t Button_state() {
	
	static uint16_t smillis = 0;
	static uint8_t flag = 0;
	static uint8_t flag2 = 0;
	
	if(bit_is_clear(PINB,0))
	{
		if(!flag2) {cli(); bcount=0; sei(); flag2=1;}
		if(!smillis) smillis = bcount;
		if(!flag && bcount-smillis > 500)
		{
			flag = 1;
			//PORTB ^=_BV(1);
			return Long_press;
		}
		//else Long_press = 0
	}
	
	if(smillis && !(bit_is_clear(PINB,0)))
	{
		if(bcount-smillis <= 500 && bcount-smillis > 20) return Short_press; //PORTB ^=_BV(2);
		//else Short_press = 0;
		smillis = 0;
		flag = 0;
	}
	
	flag2 = 0;
}

Не работает((в вайле просто пытаюсь инвертировать значение пина, светодиод тупо горит...

while (1)
	{
		read_encoder();
		Button_state();
		separation(Timer_count);
		if(Long_press) PORTB ^=_BV(1);
		//if(Short_press) PORTB ^=_BV(2);
    }

 

 Интересней то, что если реализовывать весь функционал напрямую в функции Button_state(), то все работает как положено, но... функция есть функция, по моему мнению, она должна выполнять только свою работу.

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

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

0 таймер работает с частотой 125000 Гц, а 2 работает в асинхронном режиме от внешнего часового кварца

Это чудесно, но вычислить частоту прерываний от них вы предлагаете мне?

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

if(bcount-smillis <= 500 && bcount-smillis > 20) return Short_press;

//PORTB ^=_BV(2); //else Short_press = 0;

smillis = 0; flag = 0;

Вы учитываете, что если условие у вас истинное, обнуления smillis и flag не происходит?

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

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

static void key_repeater(char kk){
   TIMER(TR, 0, 0); // программный таймер
   static char old_kk;

   if(kk == 0){
      timer_stop(&TR);
   } else {
      if(old_kk != kk){
         timer_start(&TR, 1000, 0); // запуск таймера на "долгий" интервал
         put_message(QUEUE, MSG_KEY, kk, 0);
      } else {
         if(timeout(&TR)){
            timer_start(&TR, 300, 0); // запуск таймера на "короткий" интервал
            put_message(QUEUE, MSG_KEY, kk, 0);
         }
      }
   }
   old_kk = kk;
}

Я пользуюсь вот такой функцией (см. выше). В параметре этой функции код нажатой кнопки, который получается просто опросом порта каждые 50 мс. 

Функция put_message помещает код кнопки в очередь для обработки в главном цикле - при желании можно и результат возвращать вместо очереди. Эта функция различает короткие и длинные нажатия (после длинногг начинает автоповтор). Программные таймеры я описывал в своем "блоге".

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

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

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

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

@WinneR , судя по вопросительному знаку в конце предложения, был именно вопрос :)
Ваша ошибка сразу в глаза бросается, на что ARV и указал. Или его вопрос ни о чём Вам не говорит ?

 

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

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

@WinneR , судя по вопросительному знаку в конце предложения, был именно вопрос :)
Ваша ошибка сразу в глаза бросается, на что ARV и указал. Или его вопрос ни о чём Вам не говорит ?

 

Я просто в контексте предложения не понял, что имеется ввиду. По поводу ошибки функция неоднократно использовалась мной и не только мной. Единственное, что я добавил, это обнуление переменной при нажатии кнопки. И ещё раз повторюсь ЕСЛИ РЕАЛИЗОВЫВАТЬ ТОТ ФУНКЦИОНАЛ, КОТОРЫЙ МНН НУЖЕН ВНУТРИ ЭТОЙ ФУНКЦИИ, ТО ВСЁ РАБОТАЕТ КАК ПОЛОЖЕНО. 

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

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

ЕСЛИ РЕАЛИЗОВЫВАТЬ ТОТ ФУНКЦИОНАЛ, КОТОРЫЙ МНН НУЖЕН ВНУТРИ ЭТОЙ ФУНКЦИИ, ТО ВСЁ РАБОТАЕТ КАК ПОЛОЖЕНО. 

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

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

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

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

Нее, неё я не кричу) :rolleyes: Просто я хочу прописать основной функционал не в функции Button_state, а в основном цикле программы. Для этого мне нужно возвращать функцией значение переменных и работать уже с ними. Значение то возвращаются, но работает код некорректно. Вот в этом и проблема. Насчёт рабочего кода, скину вечером, как приду с работы. 

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

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

Покажите код, который работает

Итак проблему с кодом я частично решил)) Но есть нюанс, обнуление таймера происходит только при повторном нажатии кнопки сброса... почему так? этого я пока не пойму. И ещё вопрос специалистам, почему если не делать return в функции Button_state, она тупо не работает,  таймер не стартует???? Вот сам код.

#include "add.h"

uint8_t NUM[12] = {63, 6, 91, 79, 102, 109, 125, 7, 127, 111, 57, 99};  // 9 0b01101111
//                 0   1  2   3    4    5    6   7   8    9   C   о

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

uint16_t Timer_count = 0; // число для отсчёта таймером
bool Timer_status = 0; // статус таймера
volatile bool Timer_finished = 0; // завешение раблты таймера


void read_encoder() {
	
	static bool a=0;
	if (!a)
	{
		if (Up0||Down0)
		{
			a=1;
			if (Up0) {
				if(!Timer_status) if (Timer_count<9999) Timer_count++;
				}
			
			if (Down0) {
				if(!Timer_status) if (Timer_count>0) Timer_count--;
			}
		}
	}
	
	if (Up1&&Down1) a = 0;
	
}


void Button_state(bool *lp, bool *sp) {
	
	static uint16_t smillis = 0;
	static uint8_t flag = 0;
	static uint8_t flag2 = 0;
	
	if(bit_is_clear(PINB,0))
	{
		if(!flag2) {cli(); bcount=0; sei(); flag2=1;}
		if(!smillis) smillis = bcount;
		if(!flag && bcount-smillis > 500) { 
			flag = 1;
			(*lp) = 1;
		}
		else (*lp) = 0;
	}
	
	if(smillis && !(bit_is_clear(PINB,0)))
	{
		if(bcount-smillis <= 500 && bcount-smillis > 20) (*sp) = 1;
		else (*sp) = 0;
		
		smillis = 0;
		flag = 0;
	}
	return 0;
	flag2 = 0;
}

ISR(TIMER2_OVF_vect) {

	if( Timer_status && Timer_count != 0) Timer_count--;
	
	
	if(Timer_count==0 && Timer_status) {
		if(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); }
	if(i==2) { OFF(1); PORTD = NUM[N3]; ON(2); }
	if(i==3) { OFF(2); PORTD = NUM[N4]; ON(3); }
	
}


int main(void)
{
	
	bool Long_press = 0;  // длительное нажаие кнопки
	bool Short_press = 0; // корткое нажаие кнопки
	
	DDRD = 255;
	PORTD = 0; // разряды
	
	DDRC = 0b00001111;
	PORTC = 0; // сегменты, + - энкодера
	
	DDRB |=(1<<2) | (1<<1); // светодиоды, кнопка энкодера
	PORTB = 0b00000000;
	
	cli();
	TIMSK |= (1 << TOIE0);
	TCCR0 |= (1<<CS01) | (1<<CS00);
	TCCR0 &= ~((1<<CS02)); // | (1<<CS00)); // без предделителя
	TCNT0 = 0;
	
	
	ASSR |= (1 << AS2); // Включаем асинхронный режим T2
	TCNT2 = 0; // Сбрасываем регистр счета
	while(ASSR != (0b00001000)) asm ("nop"); // дожидаемся разрешения на запись
	TCCR2 = 0b00000101; // Предделитель на 128
	TIMSK |= (1 << TOIE2); // Разрешаем прерывание по переполнению
	TIFR = 0;
	
	
	sei();
	
	
	while (1)
	{
		read_encoder();
		Button_state(&Long_press, &Short_press);
		separation(Timer_count);
		
		if(Short_press) if(!Timer_status) Timer_status = 1;  // короткое нажатие, запуск таймера
		
		if(Long_press) { // длительное нажатие кнопки, обнуление срабатывания таймера
			if(Timer_count==0 && !Timer_status) {
				if(Timer_status) Timer_status=0;
				PORTB &=~_BV(1);
			}
		}	
    }
}

 

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

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

Бросилось в глаза :

	return 0;
	flag2 = 0;

Тут всё в порядке ? :wacko:

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

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

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

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

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

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

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

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

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

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

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

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