Микроконтроллеры, АЦП, память и т.д Темы касающиеся микроконтроллеров разных производителей, памяти, АЦП/ЦАП, периферийных модулей... |
08.03.2011, 17:28
|
|
Частый гость
Регистрация: 01.01.2011
Сообщений: 31
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
WinAvr Atmega L297 L298
Ребят схожу с ума:
Разрабатываю контроллер ШД с указанной связкой в теме.
Требуется получить определенное кол-во импульсов (здесь 10) с определенным периодом (здесь 1 с) на PB3. Таймер настроен на 250 (TCNT=0x06) тактов с делителем на 8 (TCCR0=(0‹‹CS00)|(1‹‹CS01)|(0‹‹CS02) ![Прикольно](images/smilies/icon_wink3.gif) , переменная count_T - флаг для обсчета временного интервала. Проблема стоит в том, что проверка нуля на линии PB3 совсем не проходит (if (bit_is_0(PINB,3)) {sig_clock(freq_in,step_in,count_T); }), как не пробовал. Пробовал делать без проверки, просто запускал функцию sig_clock - ведет себя мягко говоря странно. подозреваю, что где-то конкретный косяк в таймере или в возвращении count_T.
Я уже измучился, если идей не будет совершу самое жестокое сделаю все на _ms_delay(freq_f). Помогите)
Код:
|
#define F_CPU 4000000UL
#include ‹avr/io.h›
#include ‹avr/interrupt.h›
#include ‹util/atomic.h›
#define bit_is_0(reg, bit) (!(reg & (1‹‹(bit))))
volatile unsigned int count_T=0;
ISR(TIMER0_OVF_vect){
count_T++;
TCNT0=0x06;
};
void sig_clock(volatile unsigned int freq_f, volatile unsigned int step_f, volatile unsigned int count_f)
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
for (unsigned int a=0;a‹step_f;a++){
if (count_f==freq_f) {
PORTB^= _BV(PB1);
step_f--;
count_f=0;
}
}
}
}
int main(void){
volatile unsigned int freq_in=0;
volatile unsigned int step_in=0;
DDRB=0x07;
PORTB=0x09;
TIMSK=(1‹‹TOIE0);
TCCR0=(0‹‹CS00)|(1‹‹CS01)|(0‹‹CS02);
TCNT0=0x06;
sei();
freq_in=1000; //период 1000 мс
step_in=10; //кол-во импульсов
while(1){
if (bit_is_0(PINB,3)) {sig_clock(freq_in,step_in,count_T); }
}
}; |
Последний раз редактировалось Sho_otnik; 08.03.2011 в 17:49.
|
|
|
|
09.03.2011, 19:42
|
|
Прохожий
Регистрация: 29.03.2010
Сообщений: 3
Сказал спасибо: 4
Сказали Спасибо 1 раз в 1 сообщении
|
Re: WinAvr Atmega L297 L298
А для чего строчки
step_f--;
count_f=0;
в процедуре sig_clock? Сложилось впечатление, что Вы пытаетесь изменить step_in и count_T соответствено. Так не получится.
|
|
|
|
09.03.2011, 20:24
|
|
Прописка
Регистрация: 17.10.2010
Сообщений: 113
Сказал спасибо: 2
Сказали Спасибо 20 раз(а) в 12 сообщении(ях)
|
Re: WinAvr Atmega L297 L298
Sho_otnik, если не трудно - можете выложить то же самое с комментариями, что в какой строчке делаете ... разгадывать ход мысли без них - можно, но можно и не угадать. Конечно, если Вас не затруднит .
|
|
|
Сказали "Спасибо" avtoneru
|
|
|
10.03.2011, 17:16
|
|
Частый гость
Регистрация: 01.01.2011
Сообщений: 31
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: WinAvr Atmega L297 L298
Задача стоит тривиальная, задаем с клавиатуры кол-во импульсов и период, нажимаем кнопку и с ножки выходят заданное кол-во и с определенным периодом прямоугольные импульсы. Не получается нифига.
Код:
|
#define F_CPU 4000000UL
#include ‹avr/io.h›
#include ‹avr/interrupt.h›
#include ‹util/atomic.h›
#define bit_is_0(reg, bit) (!(reg & (1‹‹(bit)))) //макрос проверки 0 на линии порта
volatile unsigned int count_T=0; //объявляем count_T как "летучую" переменную
ISR(TIMER0_OVF_vect){ //выполняем действие по переполнению таймера0
//count_T++; // переменная для определения периода импульса, т.е.
//если нам нужно получить период в 200 мс, нам нужно, чтобы
//count_T=200 :)
//TCNT0=0x06; //таймер настроен на 250 тактов, т.е. на частоте 4Мгц
//переполнение будет осуществлятся через 500 мкс
};
void sig_clock(volatile unsigned int freq_f, volatile unsigned int step_f, volatile unsigned int count_f) //функция выдачи определенного кол-ва
//импульсов с определенным периодом.
{
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { //атомарный блок, где
//запрещены прерывания, чтобы во время выполнения данной функции
//переменаня count_T в таймере не обрабатывалась
for (unsigned int a=0;a‹step_f;a++){ //цикл для установления кол-ва
//импульсов.
if (count_f==freq_f) { //условие для определения периода, если
//мы задали период freq_f=200 мс, то следственно условие будет
//истинным, только тогда, когда count_T=200.
PORTB^= _BV(PB1); //изменяем состояние пина PB1 (получаем
//возрастающий фронт, на следующем цикле через 200мс спадающий)
step_f--; //дискрементируем переменную step_f для отсчета
//кол-ва импульсов.
count_f=0;//сбрасываем в 0 count_f, для того чтобы условие
//определения периода смогло выполнится снова.
}
}
}
}
int main(void){
volatile unsigned int freq_in=0; //переменная для определения периода
volatile unsigned int step_in=0; //переменная кол-ва импульсов
DDRB=0x07;
PORTB=0x09;
TIMSK=(1‹‹TOIE0);
TCCR0=(0‹‹CS00)|(1‹‹CS01)|(0‹‹CS02); //таймер с предделителем 8
TCNT0=0x06; //начинаем считать с 6, чтобы кол-во тактов до переполнения было 250
sei();
freq_in=1000; //период 1000 мс
step_in=10; //кол-во импульсов
while(1){
if (bit_is_0(PINB,3)) {sig_clock(freq_in,step_in,count_T); }//реализация
//кнопки, когда кнопка нажата вызываем функцию sig_clock
}
}; |
|
|
|
|
10.03.2011, 17:26
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
|
Re: WinAvr Atmega L297 L298
Сообщение от Sho_otnik
|
Задача стоит тривиальная, задаем с клавиатуры кол-во импульсов и период
|
И где клавиатура?
Сообщение от Sho_otnik
|
нажимаем кнопку и с ножки выходят заданное кол-во и с определенным периодом прямоугольные импульсы.
|
Один раз выходить должны или повторяться если кнопку не отпустили?
|
|
|
|
10.03.2011, 17:36
|
|
Частый гость
Регистрация: 01.01.2011
Сообщений: 31
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: WinAvr Atmega L297 L298
клавиатуры в коде нет, это "вырезка"
Один раз выходить
|
|
|
|
10.03.2011, 18:08
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
|
Re: WinAvr Atmega L297 L298
Ну тогда и цифры дайте - минимальный/максимальный период, необходимый коэффицент заполнения.
|
|
|
|
10.03.2011, 18:14
|
|
Частый гость
Регистрация: 01.01.2011
Сообщений: 31
Сказал спасибо: 13
Сказали Спасибо 0 раз(а) в 0 сообщении(ях)
|
Re: WinAvr Atmega L297 L298
Период: 1КГц (1мс) - 0,1Гц (10 с) (точнее 9999 мс)
Кол-во импульсов от 1 до 10000 (точнее 9999)
Т.е. подразумевается использовать 2 4-ёх разрядных индикатора. Вводим частоты и кол-во. Реализовываем программно с помощью массива, потом считаем, примерно так значения частоты и кол-ва:
Код:
|
freq_in=step[0]*1000+step[1]*100+step[2]*10+step[3];
step_in=step[4]*1000+step[5]*100+step[6]*10+step[7]; |
|
|
|
|
10.03.2011, 19:12
|
|
Прохожий
Регистрация: 29.03.2010
Сообщений: 3
Сказал спасибо: 4
Сказали Спасибо 1 раз в 1 сообщении
|
Re: WinAvr Atmega L297 L298
Переменная count_T у вас будет считать от 0 до 65535, а не от 0 до 200, как Вы того хотите (при условии, что Вы разкомментируете код в обработчике прерывания). Вы пишите count_f=0, но это не обнулит Вашу глобальную переменную count_T. Вы передаете в функцию только значение переменной count_T, а не ее саму. Для того чтобы функция могла изменить внешнюю переменную, нужно передавать указатель на эту переменную.
|
|
|
|
10.03.2011, 19:38
|
|
Почётный гражданин KAZUS.RU
Регистрация: 13.12.2004
Сообщений: 3,172
Сказал спасибо: 11
Сказали Спасибо 692 раз(а) в 504 сообщении(ях)
|
Re: WinAvr Atmega L297 L298
Вот накидал на скорую руку.
Код:
|
#include ‹avr/io.h›
#include ‹avr/interrupt.h›
#include ‹stdint.h›
#define OUT_PORT PORTB
#define OUT PB3
typedef volatile struct
{
uint8_t fl_work :1; // флаг индицирующий включенный вывод
uint8_t fl_start :1; // флаг старта вывода
uint8_t fl_tick :1; // тик таймера, можно использовать для синхронизации чего попало
// например опроса клавы и динамической индикации
} flags_t;
uint16_t volatile PERIOD;
uint16_t volatile IMP_COUNT;
flags_t flags;
ISR(TIMER0_OVF_vect)
{
static uint16_t st_inv_count; // счетчик изменений вывода
static uint16_t st_period; // период
static uint16_t st_time; // таймер изменения
if(flags.fl_work) // проверим идет ли уже вывод
{
// вывод запущен
if(st_time == 0) // проверим не пора ли изменить состояние выхода
{
// пора изменить
OUT_PORT ^= (1‹‹OUT); // собственно изменение на противоположное
st_inv_count--; // на одно изменение меньше осталось
if(st_inv_count == 0) // не все ли вывели?
{
// все, больше не нужно
flags.fl_work = 0; // вывод закончен
}
else
{
// вывели не все
st_time = (st_period ›› 1)-1; // в таймер время до следующего изменения
} // if(st_inv_count == 0)
}
else
{
// еще подождем изменять, время не пришло
st_time--;
} // if(st_time == 0)
}
else
{
// вывод не запущен
if(flags.fl_start) // может нужно запустить?
{
// нужно запустить
OUT_PORT ^= (1‹‹OUT); // первое изменение на противоположное
st_inv_count = (IMP_COUNT ‹‹ 1)-1; // счетчик изменений
st_period = PERIOD; // сохраним период
st_time = (st_period ›› 1); // время до следующего изменения на одно меньше половины периода
flags.fl_start = 0; // старт отработан
flags.fl_work = 1; // начался вывод
} // if(flags.fl_start)
} // if(flags.fl_work)
// Тут перевзводим таймер
// если нужен минимальный джиттер, то надо принять меры по его минимизации
// по простому же
TCNT0 += 6;
flags.fl_tick = 1;
} // ISR(TIMER0_OVF_vect)
int main(void)
{
DDRB |= (1‹‹OUT);
TIMSK=(1‹‹TOIE0);
TCNT0 = 6;
TCCR0=(0‹‹CS00)|(1‹‹CS01)|(0‹‹CS02);
PERIOD = 5; // период в попугаях
IMP_COUNT = 4; // счетчик импульсов
sei();
while(1)
{
flags.fl_start = 1;
while(flags.fl_start){}; //ждем начала
// изменим период, это не повлияет на уже начатый вывод
PERIOD += 1;
IMP_COUNT += 1;
while(flags.fl_work){}; // ждем окончания вывода
// и повторим с новыми значениями периода и числа импульсов
}
} |
Последний раз редактировалось kison; 10.03.2011 в 20:03.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 13:20.
|
|