Обсуждаем контроллеры компании Atmel.
Ответить

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 11:45:41

Подскажите почему не видит в коде глобальную переменную Danue в среде WinAVR. Что не так делаю. Вот снимок. вот сам код.

Спойлер/*
* USARTATMEGA8.c
*

*/


#include <avr/io.h>
#define F_CPU 4000000
#define BAUD 9600L // Скорость обмена данными
#define UBRRL_value (F_CPU/(BAUD*16))-1
unsigned char Danue=0;

int main(void)

{
/*Настраиваем соответствующий порт передачи на выход*/
PORTD|=(1<<PD1);
/*Устанавливаем бит разрешение передачи*/
UCSRB|=(1<<TXEN);
//Переходим в регистр UCSRC
UCSRC|=(1<<URSEL);
//Размер передоваемого слова выставляем на 8 бит.*/
UCSRC|=(1<<UCSZ1)|(1<<UCSZ0);
//Выбираем режим работы ассинхронный
UCSRC&=~(1<<UMSEL);
//Проверка на четность выставляем в ноль
UCSRC&=~(1<<UPM1)&(1<<UPM0);
//Количество стоп битов также ставим 1
UCSRC&=~(1<<USBS);
//Устанавливают скорость передачи в бодах
UCSRC&=~(1<<URSEL);//Переходим в регистр UBRR;
UBRRL=UBRRL_value;//Младший бит
UBRRH=0x00;//Старший бит

/*Передаем наши данные через UDR всего один раз. */
//UDR=0x45;
while(1)
{

//Проверяем флаг UDRE — флаг опустошения регистра передатчика,
//устанавливается в 1 при пустом буфере передатчика — UDR значит можно передовать;
if ((Danue==0)&&(UCSRA|(1<<UDRE)))
{ //Отправляем только один раз
Danue++;

UDR=0x45;

}
if ((Danue==1)&&(UCSRA|(1<<UDRE)))
{ //Отправляем только один раз
UDR=0x53;
Danue++;
}
}
}
Вложения
8888.png
(126.03 KiB) Скачиваний: 436

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:00:31

Компилятор при оптимизации увидел, что она фактически не используется, поэтому её выбросил и сгенерировал код наподобие:
Код:
if (UCSRA | (1<<UDRE))
    UDR=0x45;
if (UCSRA | (1<<UDRE))
    UDR=0x53;
while(1) {}
Думаю, дело именно в этом.

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:09:14

Подскажите а как мне ее задействовать Danue в условии, так как в отношении этой переменной должно срабатывать условие.
Код:
 if ((Danue==0)&&(UCSRA|(1<<UDRE)))
        { //Отправляем только один раз
    
      Danue=1;
    
         UDR=0x45;
         
        }

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:12:31

WiseLord писал(а):Думаю, дело именно в этом
либо сделал ее регистровой (я не вникал в логику использования переменной).

Добавлено after 1 minute 38 seconds:
strengerst писал(а):а как мне ее задействовать Danue в условии
а это на самом деле надо? судя по комментарию вам нужно выдать данные в USART один раз - ну так и выдавайте ВНЕ цикла. будет один раз.

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:15:04

Мне для понимания для себя что бы знать. На коменты не смотрите. Как сделать ее не регистровой.

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:20:18

strengerst писал(а):Как сделать ее не регистровой
сделайте ее static

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:27:36

Не помогло. Делал так
Код:
static unsigned char  Danue=0;

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:44:44

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

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:49:18

Ну я хочу создать условие, в котором переменная принимает те или иные значения и в отношении нее сделать действия, как мне это провернуть.
Спасибо volatile помогло. Пойду по кривой дорожке.
Последний раз редактировалось strengerst Ср дек 14, 2016 13:52:50, всего редактировалось 1 раз.

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:52:46

В какой-то момент компилятор посчитает нецелесообразным её выбрасывать, и станет всё нормально. Но пока, в таком виде, она не нужна. Ну, или сделайте-таки volatile, на время отладки.

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 13:53:32

Спасибо volatile помогло.
Подскажите сколько должна быть задержка между оправками данных по USART.
Без задержки я так понимаю отправлять друг за другом данные нельзя пока буфер не очистится.
Если я делаю с задержкой то в терминале протеуса все корректно отображается, а если без нее то только первое условие.
А второе нет.
Код:
if ((UCSRA||(1<<UDRE))&&(Danue==0))
{ //Отправляем только один раз
UDR=0x45;
Danue++;
}
_delay_ms(1000);
if ((UCSRA||(1<<UDRE))&&(Danue==1))
{ //Отправляем только один раз
UDR=0x53;
Danue++;
}

Re: WinAvr в вопросах и ответах

Ср дек 14, 2016 17:51:07

В даташите приведены функции передачи байта на UART, перед отправкой ожидающие опустошения буфера. Проще говоря, ждут, пока не поднимется флаг UDRE

Re: WinAvr в вопросах и ответах

Чт дек 15, 2016 09:48:36

Спасибо это я понял. но не понятно почему не работает условие без задержки delay. Ну вот код ниже в нем в условии указано что только при опустошении буфера UDRE (то есть когда он в 1 то буфер пуст и данные можно передавать), передать данные UDR=0x45;
и прибавить 1 к переменной Danue. Условие выполняется а вот второе точно такое же условие уже не выполняется. Почему? А вот если поставить между условиями задержку в 1 секунду. Все работает.
Рабочий код
Спойлер
Код:
if ((UCSRA||(1<<UDRE))&&(Danue==0))
{ //Отправляем только один раз
UDR=0x45;
Danue++;
}
_delay_ms(1000);
if ((UCSRA||(1<<UDRE))&&(Danue==1))
{ //Отправляем только один раз
UDR=0x53;
Danue++;
}



Не рабочий код (Второе условие не передается)
Спойлер
Код:
if ((UCSRA||(1<<UDRE))&&(Danue==0))
{ //Отправляем только один раз
UDR=0x45;
Danue++;
}
if ((UCSRA||(1<<UDRE))&&(Danue==1))
{ //Отправляем только один раз
UDR=0x53;
Danue++;
}

Весь этот код находиться в цикле while(1) функции int main(void);

Re: WinAvr в вопросах и ответах

Чт дек 15, 2016 09:59:28

strengerst писал(а):но не понятно почему не работает условие без задержки delay
потому что вы ошибаетесь в записи логических выражений.

strengerst писал(а):UCSRA||(1<<UDRE)
вот это выражение истинно ВСЕГДА. изучите битовые манипуляции над переменными, например, вот по этой моей заметке: http://arv.radioliga.com/content/view/191/49/

Re: WinAvr в вопросах и ответах

Чт дек 15, 2016 10:00:33

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

if ((tmp & (1<<2)) != 0 ){
// блок будет выполняться, только если установлен
// второй бит переменной tmp
}

if ((tmp & (1<<2)) == 0 ){
// блок будет выполняться, только если не установлен
// второй бит переменной tmp
}


if ((UCSRA & (1<<UDRE)) != 0 ){
// блок будет выполняться, только если установлен
// UDRE бит переменной tmp
}

if ((UCSRA & (1<<UDRE)) == 0 ){
// блок будет выполняться, только если не установлен
// UDRE бит переменной UDRE=1
}

Или так:

if (~(UCSRA | ~(1<<UDRE))== 0 ){
// блок будет выполняться, только если установлен
// UDRE бит переменной UDRE=1

}

Re: WinAvr в вопросах и ответах

Пт дек 16, 2016 10:35:08

Помогите найти ошибку в приемнике. Почему не выполняется условие if(Zeto==0x56) {PORTD|=(1<<PD5);Zeto++;}
Я понимаю что из-за того что Zeto не равно 0x56. Но почему? Мы ведь считываем данные после отправки с UDR а там точно 0x56?
Спойлер
Код:
/*
* USARTATMEGA8.c
*

*/


#include <avr/io.h>
#define F_CPU 4000000
#define BAUD 9600L // Скорость обмена данными
#define UBRRL_value (F_CPU/(BAUD*16))-1 //volatile unsigned char Danue=0;
 unsigned char Danue=0;
 unsigned char Zeto=0;
int main(void)

{
PORTD|=(1<<PD4);
/*Настраиваем соответствующий порт передачи на вход*/
PORTD&=~(1<<PD0);
/*Устанавливаем бит разрешение приема*/
UCSRB|=(1<<RXEN);
//Переходим в регистр UCSRC
UCSRC|=(1<<URSEL);
//Размер принимаемого слова выставляем на 8 бит.*/
UCSRC|=(1<<UCSZ1)|(1<<UCSZ0);
//Выбираем режим работы ассинхронный
UCSRC&=~(1<<UMSEL);
//Проверка на четность выставляем в ноль
UCSRC&=~(1<<UPM1)&(1<<UPM0);
//Количество стоп битов также ставим 1
UCSRC&=~(1<<USBS);
//Устанавливают скорость передачи в бодах
UCSRC&=~(1<<URSEL);//Переходим в регистр UBRR;
UBRRL=UBRRL_value;//Младший бит
UBRRH=0x00;//Старший бит

/*Принимаем наши данные через RXD всего один раз. */   
while(1)
{

//Проверяем флаг RXC флаг завершения приема, устанавливается в 1 при наличие непрочитанных данных в буфере приемник — UDR; — флаг опустошения регистра передатчика,

   //(UCSRA & (1<<UDRE)) - производит чтение бита.
   //UCSRA ^(1<<UDRE) - инверсия.
if ((UCSRA & (1<<RXC))!= 0 ){
if (Danue==0)
{ //Отправляем только один раз
 Zeto=UDR;
Danue++;
}}
   if(Zeto==0x56)
   {PORTD|=(1<<PD5);
      Zeto++;
      }
   
   
}
}
Вложения
яяяя.png
(65.45 KiB) Скачиваний: 275
яяя.png
(30.8 KiB) Скачиваний: 420

Re: WinAvr в вопросах и ответах

Пт дек 16, 2016 11:37:47

Уберите условие if (Danue==0), принимайте данные всегда и весь UDR кидайте в PORTB, так будет нагляднее понять что Вы приняли на самом деле.

Самая распространенная ошибка работы с УАРТ, это не правильная настройка скорости. В протеусе то выставили частоту МК? А может Вы не с теми параметрами отправляете данные?

Re: WinAvr в вопросах и ответах

Пт дек 16, 2016 12:14:43

Да в роде в настройках все правильно поставил. Вот снимок. Подправил код
Спойлер
Код:
if ((UCSRA & (1<<RXC))!= 0 ){

 Zeto=UDR;

}
   if(Zeto==0x56)
   {PORTD|=(1<<PD5);
      Zeto++;
      }
   
Вложения
pppp.png
(104.25 KiB) Скачиваний: 425
cccc.png
(134.55 KiB) Скачиваний: 420

Re: WinAvr в вопросах и ответах

Вс дек 25, 2016 09:00:19

Доброго времени суток.
Столкнулся с проблемой в winavr.
Вот, к примеру, простенькая программа:
Спойлер
Код:
#include <avr/io.h>
#include <avr/interrupt.h>  /* для sei() */
#include <util/delay.h>     /* для _delay_ms() */


#define KN_PORT    PORTD    // порт
#define KN_DDR    DDRD
#define KN_PIN    PIND   
#define KN       0      // пин кнопка


unsigned int last_millis=0;
char   i=0;


// Timer 0 overflow interrupt service routine
ISR( TIMER0_OVF_vect )
{
// Reinitialize Timer 0 value
TCNT0=0xB2;
// Place your code here
last_millis++;

}



char skan_klav (char Pin_Set, volatile char *PORT_set) {

   last_millis = 0; // 10 милли секунд
   
   if ((*PORT_set & (1<<Pin_Set)) == 0) {
    _delay_ms (50);
   
     do { } while ((*PORT_set & (1<<Pin_Set)) == 0); // проверить отжата ли кнопка
   _delay_ms(30);
   
   
     if (last_millis > 25) {
      return 1;
      }
    
     if (last_millis > 200) {
      return 2;
      }
   return 100;
   }

   return 0;   
};

int main(void)
{

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 7,813 kHz
TCCR0 |= (1<<CS02) | (0<<CS01) | (1<<CS00);
TCNT0=0xB2;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK |= (1<<TOIE0);


   KN_DDR |= (0<<KN); 
   KN_PORT |= (1<<KN);
   
   sei();

for(;;){     

   i = skan_klav (KN, &KN_PIN);
   
   _delay_ms(500);
   
   i = 0;
   
   }

};
Интересует вот этот кусок кода:
Спойлер
Код:
char skan_klav (char Pin_Set, volatile char *PORT_set) {

   last_millis = 0; // 10 милли секунд
   
   if ((*PORT_set & (1<<Pin_Set)) == 0) {
    _delay_ms (50);
   
     do { } while ((*PORT_set & (1<<Pin_Set)) == 0); // проверить отжата ли кнопка
   _delay_ms(30);
   
   
     if (last_millis > 25) {
      return 1;
      }
    
     if (last_millis > 200) {
      return 2;
      }
   return 100;
   }

   return 0;   
};
Этот кусок кода не выполняется по заложенному в него алгоритму.
Тем более дизассемблер показывает следующее
СпойлерИзображение
По чему часть кода не обрабатывается?
В архиве проект, протеус, и есе файлы.
Вложения
Primer.rar
(23.57 KiB) Скачиваний: 222

Re: WinAvr в вопросах и ответах

Вс дек 25, 2016 16:22:22

Не сильно вникая в суть проблемы, спрошу: почему глобальная переменная, last_millis, которая изменяется в прерывании, не объявлена как volatile?
Ответить