Мелкие вопросы по МК и ПЛИС.
Сделал светодиодную моргалку на Tiny2313. С завода она поставляется с запущенным встроенным генератором на 4 МГц и делителем на 8. Фьюзы не трогал. Для эффекта мигания циклом for( ; ; ) сделал задержку из 65536 nop'ов (понимаю, не лучший вариант). Расчетное время составило 65536·8/4·10^6 = 0,13 с. На самом деле мигает почти в30 раз медленнее (около 3 с). Где я ошибся?
- Реклама
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
Я по даташиту вычитал, что 4 МГц (+делитель на 8 ). Но все равно - отличие было бы в 2 раза, да и то в быструю сторону.
Вот исходник:
main()
{
#include <iot2313v>
long i;
DDRB = 0x1C; //установили 14...16 ноги на вывод
begin: //начало программы
PORTB = 0x10; //зажгли красный светодиод
for (i=0;i<65535;i++) #asm("nop"); //задержка
PORTB = 0x08; //зажгли желтый светодиод
for (i=0;i<65535;i++) #asm("nop");
PORTB = 0x04; //зажгли зеленый светодиод
for (i=0;i<65535;i++) #asm("nop");
goto begin; //переход к началу
}
Вот исходник:
main()
{
#include <iot2313v>
long i;
DDRB = 0x1C; //установили 14...16 ноги на вывод
begin: //начало программы
PORTB = 0x10; //зажгли красный светодиод
for (i=0;i<65535;i++) #asm("nop"); //задержка
PORTB = 0x08; //зажгли желтый светодиод
for (i=0;i<65535;i++) #asm("nop");
PORTB = 0x04; //зажгли зеленый светодиод
for (i=0;i<65535;i++) #asm("nop");
goto begin; //переход к началу
}
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
а оператор for по вашему сколько тактов занимает, да еще и с long i? (сам отвечу приблизительно тактов 30 и занимает). Подсказка: чтобы получить точные временные интервалы используйте таймер и прерывания (ну или на худой конец полинг флагов таймера).Gudd-Head писал(а):Я по даташиту вычитал, что 4 МГц (+делитель на 8 ). Но все равно - отличие было бы в 2 раза, да и то в быструю сторону.
Вот исходник:
main()
{
#include <iot2313v>
long i;
DDRB = 0x1C; //установили 14...16 ноги на вывод
begin: //начало программы
PORTB = 0x10; //зажгли красный светодиод
for (i=0;i<65535;i++) #asm("nop"); //задержка
PORTB = 0x08; //зажгли желтый светодиод
for (i=0;i<65535;i++) #asm("nop");
PORTB = 0x04; //зажгли зеленый светодиод
for (i=0;i<65535;i++) #asm("nop");
goto begin; //переход к началу
}
- Реклама
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
Я не спец в Си, но наверняка код на ассемблере сгенерированный компилятором зависит от оптимизации типа переменных и т. п., т. е. не всегда один и тот же. Посмотреть кроме как в асм листинге вряд-ли возможно (точнее наверное все-же возможно, но сложно довольно и нудно), в общем, пусть меня знатоки поправят.Gudd-Head писал(а):Спасибо.
Для одного кристалла компилятор с Си на ассемблер переводит однозначно (напр., тот же оператор for( ; ; ) в 30 машинных циклов) или по-разному? И можно где-нить посмотреть как будут переведены те или иные функции (кроме скомпилированного .asm файла)?
По-поводу 30 тактов - данное высказывание основано только на вашем эксперименте, я не знаю во сколько тактов выполняется for.
Кусок из сгенерированного .asm файла:smac писал(а):По-поводу 30 тактов - данное высказывание основано только на вашем эксперименте, я не знаю во сколько тактов выполняется for.
; 6 begin:
_0x3:
; 7 PORTB = 0x10; //зажгли красный светодиод
LDI R30,LOW(16)
RCALL SUBOPT_0x0
; 8 for (i=0;i<65535;i++) #asm("nop");
_0x5:
RCALL SUBOPT_0x1
BRGE _0x6
nop
RCALL SUBOPT_0x2
RJMP _0x5
_0x6:
; 9 PORTB = 0x08; //зажгли желтый светодиод
/* Если я все правильно понимаю, здесь закомменчены строки Си и приведен их ассемблерный эквивалент с вызовом оптимизированных функций (компилятор работает в режиме оптимизации места), которые находятся в конце файла: */
;OPTIMIZER ADDED SUBROUTINE, CALLED 3 TIMES, CODE SIZE REDUCTION:10 WORDS
SUBOPT_0x0:
STS 56,R30
__CLRD1S 0
RET
;OPTIMIZER ADDED SUBROUTINE, CALLED 3 TIMES, CODE SIZE REDUCTION:18 WORDS
SUBOPT_0x1:
__GETD2S 0
__CPD2N 0xFFFF
RET
;OPTIMIZER ADDED SUBROUTINE, CALLED 3 TIMES, CODE SIZE REDUCTION:20 WORDS
SUBOPT_0x2:
__GETD1S 0
__SUBD1N -1
__PUTD1S 0
RET
Таким образом, на фоне всех этих операций задержка nop выглядит, по-крайней мере, смешной
- Сообщения: 459
- Зарегистрирован: Вс июн 01, 2008 12:16:38
Можно ли в Шаер-порграммере программировать Атмел. Если до, то на какие ноги какие сигналы подавать?
:]\/\/\/\/ххх\/\/\/\/\/\/ххх\/\/\/\/\/ххх\/\/\/\/\/\[:
В мае на гульках 2 баяна порвал...одной лапой.
Другая болела, после того, как потрогал паяльник.
В мае на гульках 2 баяна порвал...одной лапой.
Другая болела, после того, как потрогал паяльник.
ну, допустим, я делал. и что? встроенный ШИМ не обязателен для этого.Gudd-Head писал(а):Кто-нибудь делал самопальный АЦП на МК у которого нет встроенного АЦП, но есть компаратор и ШИМ? Или есть компаратор, таймер и внешний генератор пилообразного напряжения?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Доброго всем времени суток. Может кто подскажет такой вопрос: нужен синтаксис функции rand(), но той. которая работает на AVR. Ну тоесть для стандартного С++ я могу написать:
#include <stdlib>
...........
...........
X=rand(10);
...........
end;
и переменная X будет содержать случайное число в диапазоне от 0 до 10. А как такое же на AVR сделать? Заранее спасибо.
#include <stdlib>
...........
...........
X=rand(10);
...........
end;
и переменная X будет содержать случайное число в диапазоне от 0 до 10. А как такое же на AVR сделать? Заранее спасибо.
Уважаемые модераторы, сделайте пожалуйста раздел дискотечных примочек и цветомузыки. Уже много тем пылятся в бездне ветки "Умные мысли"
- Сообщения: 492
- Зарегистрирован: Вт июл 22, 2008 08:10:54
В библиотеке stdlib.h идущей с IAR находится функция int rand(void) и #define RAND_MAX 0x7FFF (тоже самое и в WinAVR). Судя по логике, изменив rand_max можно было бы задать максимальное значение, но наделе этого не произошло. В таком случае можно просто воспользоваться подобными преобразованиями: rand()&0x07 (число от 0 до 7), rand()%11 (число от 0 до 10).Inspiron писал(а):Доброго всем времени суток. Может кто подскажет такой вопрос: нужен синтаксис функции rand(), но той. которая работает на AVR. Ну тоесть для стандартного С++ я могу написать:
#include <stdlib>
...........
...........
X=rand(10);
...........
end;
и переменная X будет содержать случайное число в диапазоне от 0 до 10. А как такое же на AVR сделать? Заранее спасибо.
Подскажите пожалуйста, как на языке С запрограммировать последовательное чтение элементов массива из X целых чисел и вывод их в один из выводов порта. МК - ATMega16.
Например вот такDigital писал(а):Подскажите пожалуйста, как на языке С запрограммировать последовательное чтение элементов массива из X целых чисел и вывод их в один из выводов порта. МК - ATMega16.
Код: Выделить всё
void send_data(unsigned char *data, unsigned char n)
{
char i;
char j;
for (j=0;j<n;j++)
{
for(i=0;i<8;i++)
{
if ((data[j] & 0x80) == 0x80)
{
PORTD.0=1;
}
else
{
PORTD.0=0;
}
data[j]=data[j]<<1;
}
}
}
Вроде все понятно, комментарии нужны?
Да, пожалуйста, откомментируйте. Не понял как свой массив прикрутить к этому коду.
Строка if ((data[j] & 0x80) == 0x80), к примеру, что делает непонятно и почему переменная i ограничивается значением <8?
Мне надо к примеру выдавать в порт данные из массива (по прерыванию - переполнение таймера), т.е. первое прерывание - начальный элемент массива, второе - следующий и т.д.:
flash unsigned char array[16]={
0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00
};
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTB.4=элемент_из_массива_array;
}
Строка if ((data[j] & 0x80) == 0x80), к примеру, что делает непонятно и почему переменная i ограничивается значением <8?
Мне надо к примеру выдавать в порт данные из массива (по прерыванию - переполнение таймера), т.е. первое прерывание - начальный элемент массива, второе - следующий и т.д.:
flash unsigned char array[16]={
0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00
};
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTB.4=элемент_из_массива_array;
}
Эта строка "смотрит" на старший бит (0x80 = 0b10000000) элемента массива и смотря что на нем та часть кода и выполняется, т.е. выставляется на порту либо 1, либо 0. Так пробежав 8 раз (число бит в байте, потому i ограничено 8мью) на выходном пине получится последовательность нулей и единиц, которая соответствует числу этого элемента массива.Digital писал(а):Да, пожалуйста, откомментируйте. Не понял как свой массив прикрутить к этому коду.
Строка if ((data[j] & 0x80) == 0x80), к примеру, что делает непонятно и почему переменная i ограничивается значением <8?
чтобы вывести все элементы массива сразу то будет вот так записьМне надо к примеру выдавать в порт данные из массива (по прерыванию - переполнение таймера), т.е. первое прерывание - начальный элемент массива, второе - следующий и т.д.:
flash unsigned char array[16]={
0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00
};
void send_data(array, 16);
Для такого случая нужно немного код подкорректировать. Сейчас уже убегаю, занят, если не получится самому сделать, то вечером постараюсь отписаться.// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTB.4=элемент_из_массива_array;
}
Отпишитесь пожалуйста в любом случае. У моего домашнего компьютера с сетью проблемы и получится ли починить на выходных не знаю// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
PORTB.4=элемент_из_массива_array;
Для такого случая нужно немного код подкорректировать. Сейчас уже убегаю, занят, если не получится самому сделать, то вечером постараюсь отписаться.
}
Последний раз редактировалось Digital Пт дек 05, 2008 15:23:20, всего редактировалось 1 раз.
вполне можно заменить на строкуDigital писал(а):Да, пожалуйста, откомментируйте. Не понял как свой массив прикрутить к этому коду.
Строка if ((data[j] & 0x80) == 0x80), к примеру, что делает непонятно и почему переменная i ограничивается значением <8?
Код: Выделить всё
if (data[j] & 0x80)чтобы по прерыванию вывести ваш массив последовательно, можно сделать такой обработчик прерывания таймера:Мне надо к примеру выдавать в порт данные из массива (по прерыванию - переполнение таймера), т.е. первое прерывание - начальный элемент массива, второе - следующий и т.д.:
flash unsigned char array[16]={
0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,
0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00
};
Код: Выделить всё
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void) {
// в подпрограмме-обработчике выводится 1 байт за прерывание
// из глобального массива data[16]. байты выводятся от МЛАДШЕГО бита к СТАРШЕМУ
char i, ch = 0x01;
static char j=0;
if(j++ < 16)
for(i=0; i<8; i++) {
if (data[j] & ch)
PORTD.0=1;
else
PORTD.0=0;
ch <<= 1;
}
} P.S. в приведенном ранее примере функции send_data имеется одна неприятная особенность - после того, как эта функция отработает, ваш массив окажется обнуленным. так что будьте осторожнее, следуя советам, которые вам дают добрые люди
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!


