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

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 3
Зарегистрирован: Пн июн 12, 2017 09:10:16

Сообщение 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);



}
Вложения
Проекты.7z
(12.39 КБ) 197 скачиваний
Реклама
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

ну, если просит константу - убери переменную d и впиши блок с выводом и задержками прямо в свитч-кейс, тогда в задержку можно будет вписать константу
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Реклама
Родился
Сообщения: 3
Зарегистрирован: Пн июн 12, 2017 09:10:16

Сообщение Fizya »

[uquote="Ivanoff-iv",url="/forum/viewtopic.php?p=3125093#p3125093"]ну, если просит константу - убери переменную d и впиши блок с выводом и задержками прямо в свитч-кейс, тогда в задержку можно будет вписать константу[/uquote]
Не много не понял, весь Switch запихать в _delay_us() или наоборот?
Друг Кота
Аватара пользователя
Сообщения: 7077
Зарегистрирован: Пт ноя 11, 2016 05:48:09
Откуда: Сердце Пармы

Сообщение Ivanoff-iv »

case 1:
digitalWrite(OUTPIN, HIGH);
delayMicroseconds(4167);
digitalWrite(OUTPIN, LOW);
delayMicroseconds(4167);
break;

правда сам я делаями практически не пользуюсь - использую прерывания по таймеру
Для тех, кто не учил магию мир полон физики :)
Безграмотно вопрошающим про силовую или высоковольтную электронику я не отвечаю, а то ещё посадят за участие в (само)убиении оболтуса...
Реклама
Эиком - электронные компоненты и радиодетали
Gap
Открыл глаза
Аватара пользователя
Сообщения: 55
Зарегистрирован: Вт дек 15, 2015 23:13:32

Сообщение Gap »

Привязать переменную можно следующим образом.

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

for(int x = 0; x < N; x++)
     _delay_us(1);
где N - нужное кол-во микросекунд.
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18678
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение 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);
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

ARV писал(а):это будет плохо работать для микросекунд
Особенно на частоте процессора в 1 МГц :) Одна такая интерация растянется тактов в 10, если не больше :roll:
Так что, самый нормальный вариант для ТС'а - в каждый case свой delay.
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение 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++;
    }
}
Родился
Сообщения: 3
Зарегистрирован: Пн июн 12, 2017 09:10:16

Сообщение 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]

Ребят, больше спасибо, завтра все варианты попробую. Дружище, а не затруднит ли тебя описать каждую строчку, не пойму что делаешь...
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение 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, вроде участник форума
Ответить

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