Страница 1 из 1

Attiny2313 проблема с _delay_us()

Добавлено: Пн июн 12, 2017 10:58:29
Fizya
Здравствуйте, многоуважаемые Коты.
Я новенький в этом деле, так что прошу сильно не кусаться :))
Занимался как-то программированием в IDE Arduino и решил попробовать себя на МК, для начала поставил перед собой цель: переписать уже имеющийся код, для Attiny2313, однако при компиляции проекта(Работаю в Atmel Studio 6.2) выдала ошибку ссылаясь на переменную в ф-ции delay. Немного погуглив в мою "светлую" голову дошло, что в эту функцию можно записывать только константы, что меня очень смутило потому, что в IDE Arduino я с легкость присваивал ей переменную.
Так вот собственно в чем вопрос, можно ли как-нибудь сделать аналогичны код на Attiny?

Мои попытки написать в студии:

#define F_CPU 1000000UL // Частота ядра = 1 МГц
#include <avr/io.h>
#include <util/delay.h>

// — Макрос для управления состоянием выхода —
#define LED_BLUE_ON PORTB |= (1 « PB0) // Лог 1
#define LED_BLUE_OFF PORTB &= ~(1 « PB0) // Лог 0
int MODE = 1; // Переменная, которая определяет задержку
int DELAY = 5000; //
// Основная программа
void main(void) {
DDRD |= (0 « PD2); // Пин 6 - на вход
PORTD |= (1 « PD2); // Включаем подтягивающий (Pull-UP) резистор для пина 6
DDRD |= (0 « PD3); // Пин 7 - на вход
PORTD |= (1 « PD3); // Включаем подтягивающий (Pull-UP) резистор для пина 7

DDRB |= (1 « PB0); // Пин 12 - на вывод
// — Бесконечный цикл —
while(1) {
if( !(PIND & (1 « PD2)) ) { // Проверяем нажата ли кнопка
_delay_ms(50); // Задержка 50 мс (дребезг контактов)
while(!(PIND & (1 « PD2))); // Ждем пока кнопка не будет отпущена
if( !(PIND & (1 « PD2)) ) {
if( MODE != 11){
MODE++; // изменяем мод, тем самым изменяем саму задержку так же для вычитания
}//конец операции сложения D2
}//конец цикла первой кнопки D2
}
if( !(PIND & (1 « PD3)) ) { // Проверяем нажата ли кнопка
_delay_ms(50); // Задержка 50 мс (дребезг контактов)
while(!(PIND & (1 « PD3))); // Ждем пока кнопка не будет отпущена
if( !(PIND & (1 « PD2)) ) {
if( MODE != 1){
MODE--;
}//конец операции вычитания D3
}//конец цикла кнопки D3
}
switch(MODE) // кейсы в которых хранится время задержки
{
case 1:
DELAY = 3000;
case 2:
DELAY = 5000;
case 3:
DELAY = 6000;

}//Конец ф-ции switch
LED_BLUE_ON; // лог 1
_delay_us(DELAY);
LED_BLUE_OFF;
_delay_us(DELAY); // лог 0

} // Конец блока цикла
}
// По своей сути это генератор прямоугольных импульсов определенного диапазона, есть подобный код только на прерывания, но решил
//взять за основу его т.к. он проще

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Код на Arduino

const int OUTPIN = 9; // макрос для выхода генератора
const int Button1 = 2; // макрос кнопки
boolean lastButton1 = LOW;
boolean currentButton1 = LOW;
const int Button2 = 3;// макрос кнопки 2
boolean lastButton2 = LOW;
boolean currentButton2 = LOW;
int n = 1; //мод задержки
int d = 4166;// начальная задержка

void setup() {
pinMode(2, INPUT); // кнопки на вход
pinMode(3, INPUT);
pinMode(OUTPIN, OUTPUT); // настраеваем выход генератора на выход))

}

boolean debouance1(boolean lastButton1) // устраняем дребезг кнопок программно для кнопки 1
{
boolean currentButton1 = digitalRead(Button1);
if(lastButton1 != currentButton1)
{
delay(100);
currentButton1 = digitalRead(Button1);
return currentButton1;
}
}
boolean debouance2(boolean lastButton2)// устраняем дребезг кнопок программно для кнопки 2
{
boolean currentButton2 = digitalRead(Button2);
if(lastButton2 != currentButton2)
{
delay(100);
currentButton2 = digitalRead(Button2);
return currentButton2;
}
}
void loop()
{
currentButton1 = debouance1(lastButton1);
if (lastButton1 == LOW && currentButton1 == HIGH)
{
if(n != 15)
{
n = n + 1;
}
}
currentButton2 = debouance2(lastButton2);
if (lastButton2 == LOW && currentButton2 == HIGH)
{
if(n != 1)
{
n = n - 1;
}
}
switch(n) // ф-ция определяющая задержку
{
case 1:
d = 4167;
break;

case 2:
d = 4347;
break;

case 3:
d = 4545;
break;

case 4:
d = 4761;
break;

case 5:
d = 5000;
break;

case 6:
d = 5263;
break;

case 7:
d = 5555;
break;

case 8:
d = 5882;
break;

case 9:
d = 6250;
break;

case 10:
d = 6666;
break;

case 11:
d = 7142;
break;

case 12:
d = 7692;
break;

case 13:
d = 8333;
break;

case 14:
d = 9090;
break;

case 15:
d = 10000;
break;
}
digitalWrite(OUTPIN, HIGH);
delayMicroseconds(d);
digitalWrite(OUTPIN, LOW);
delayMicroseconds(d);



}

Re: Attiny2313 проблема с _delay_us()

Добавлено: Пн июн 12, 2017 12:49:44
Ivanoff-iv
ну, если просит константу - убери переменную d и впиши блок с выводом и задержками прямо в свитч-кейс, тогда в задержку можно будет вписать константу

Re: Attiny2313 проблема с _delay_us()

Добавлено: Пн июн 12, 2017 13:16:19
Fizya
[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=3125093#p3125093"]ну, если просит константу - убери переменную d и впиши блок с выводом и задержками прямо в свитч-кейс, тогда в задержку можно будет вписать константу[/uquote]
Не много не понял, весь Switch запихать в _delay_us() или наоборот?

Re: Attiny2313 проблема с _delay_us()

Добавлено: Пн июн 12, 2017 17:14:48
Ivanoff-iv
case 1:
digitalWrite(OUTPIN, HIGH);
delayMicroseconds(4167);
digitalWrite(OUTPIN, LOW);
delayMicroseconds(4167);
break;

правда сам я делаями практически не пользуюсь - использую прерывания по таймеру

Re: Attiny2313 проблема с _delay_us()

Добавлено: Вт июн 13, 2017 11:26:42
Gap
Привязать переменную можно следующим образом.

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

for(int x = 0; x < N; x++)
     _delay_us(1);
где N - нужное кол-во микросекунд.

Re: Attiny2313 проблема с _delay_us()

Добавлено: Вт июн 13, 2017 19:09:16
ARV
Gap писал(а):Привязать переменную можно следующим образом.

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

for(int x = 0; x < N; x++)
     _delay_us(1);
где N - нужное кол-во микросекунд.
это будет плохо работать для микросекунд, потому что накладные расходы на организацию цикла дадут погрешность на уровне тех же микросекунд. подобный подход можно рекомендовать для миллисекундных задержек или хотя бы для задержек с кратностью 10 и более микросекунд.

Добавлено after 1 minute 3 seconds:
кстати, проще можно так:

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

for(;N;N--) _delay_us(1);

Re: Attiny2313 проблема с _delay_us()

Добавлено: Вт июн 13, 2017 20:05:36
Аlex
ARV писал(а):это будет плохо работать для микросекунд
Особенно на частоте процессора в 1 МГц :) Одна такая интерация растянется тактов в 10, если не больше :roll:
Так что, самый нормальный вариант для ТС'а - в каждый case свой delay.

Re: Attiny2313 проблема с _delay_us()

Добавлено: Ср июн 14, 2017 10:29:05
oleg110592
Можно Ченовской простенькой ассемблерной функцией воспользоваться - там переменную можно
Изображение
файлик asmfunc.S:
Спойлер

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

.nolist
#include <avr/io.h>	// Include device specific definitions.
.list
#define F_CPU 8000000 
;---------------------------------------------------------------------------;
; Simple Delay
;---------------------------------------------------------------------------;
; void delay_ms(WORD ms);
; void delay_us(WORD us);

.global delay_ms
.func delay_ms
delay_ms:
	wdr			; Reset WDT
	sbiw	r24, 1		; if (ms-- == 0) return;
	brcs	9f		; /
	ldi	ZL, lo8( F_CPU / 4000 )	; 1ms delay
	ldi	ZH, hi8(F_CPU/4000)	; 
1:	sbiw	ZL, 1		; 
	brne	1b		; /
	rjmp	delay_ms
9:	ret
.endfunc


.global delay_us
.func delay_us
delay_us:
	ldi	r23, 2
1:	dec	r23
	brne	1b
	sbiw	r24, 1
	brne	delay_us
	wdr
	ret
.endfunc
пример main.c:
Спойлер

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

#include <avr\io.h>
#include <stdint.h>

volatile uint16_t k = 0;

void delay_us (uint16_t);	/* Defined in asmfunc.S */
void delay_ms (uint16_t);	/* Defined in asmfunc.S */

int main(void)
{
    DDRB = 0xFF;
    
    for (;;)
    {
        PORTB ^= 0xFF;
		delay_ms(k);
		k++;
    }
}

Re: Attiny2313 проблема с _delay_us()

Добавлено: Чт июн 15, 2017 18:45:41
Fizya
[uquote="oleg110592",url="/forum/viewtopic.php?p=3126293#p3126293"]Можно Ченовской простенькой ассемблерной функцией воспользоваться - там переменную можно
Изображение
файлик asmfunc.S:
Спойлер

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

.nolist
#include <avr/io.h>	// Include device specific definitions.
.list
#define F_CPU 8000000 
;---------------------------------------------------------------------------;
; Simple Delay
;---------------------------------------------------------------------------;
; void delay_ms(WORD ms);
; void delay_us(WORD us);

.global delay_ms
.func delay_ms
delay_ms:
	wdr			; Reset WDT
	sbiw	r24, 1		; if (ms-- == 0) return;
	brcs	9f		; /
	ldi	ZL, lo8( F_CPU / 4000 )	; 1ms delay
	ldi	ZH, hi8(F_CPU/4000)	; 
1:	sbiw	ZL, 1		; 
	brne	1b		; /
	rjmp	delay_ms
9:	ret
.endfunc


.global delay_us
.func delay_us
delay_us:
	ldi	r23, 2
1:	dec	r23
	brne	1b
	sbiw	r24, 1
	brne	delay_us
	wdr
	ret
.endfunc
пример main.c:
Спойлер

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

#include <avr\io.h>
#include <stdint.h>

volatile uint16_t k = 0;

void delay_us (uint16_t);	/* Defined in asmfunc.S */
void delay_ms (uint16_t);	/* Defined in asmfunc.S */

int main(void)
{
    DDRB = 0xFF;
    
    for (;;)
    {
        PORTB ^= 0xFF;
		delay_ms(k);
		k++;
    }
}
[/uquote]

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

Re: Attiny2313 проблема с _delay_us()

Добавлено: Пт июн 16, 2017 07:15:12
oleg110592
что делаешь...
делаю так - создаю файл в папке проекта с именем asmfunc.S (это ассемблерный файл), копирую в файл содержимое (выше), подключаю этот файл к проекту.
В файле проекта, например main.c пишем объявление функций из файла asmfunc.S:
void delay_us (uint16_t); /* Defined in asmfunc.S */
void delay_ms (uint16_t); /* Defined in asmfunc.S */
пользуемся этими функциями:
delay_ms(k);
почитать:
https://embedderslife.wordpress.com/201 ... asm-and-c/
автор YS, вроде участник форума