Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.

Обсуждаем контроллеры компании Atmel.
Ответить
Мучитель микросхем
Сообщения: 430
Зарегистрирован: Вс апр 18, 2021 15:43:55

Сообщение Kalisnik »

Новая проблема, теперь МК виснет при значении ICR1 < 850.
Спойлер

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

/*******************************************************
This program was created by the
CodeWizardAVR V3.14 Advanced
Automatic Program Generator
© Copyright 1998-2014 Pavel Haiduc, HP InfoTech s.r.l.
http://www.hpinfotech.com

Project : test_5
Version : 
Date    : 24.09.2021
Author  : 
Company : 
Comments: 


Chip type               : ATmega8A
Program type            : Application
AVR Core Clock frequency: 1,000000 MHz
Memory model            : Small
External RAM size       : 0
Data Stack size         : 256
*******************************************************/

#include <mega8.h>
#include <inttypes.h>
//#include <avr/io.h>
#include <interrupt.h>
#include <delay.h>

volatile uint8_t period = 3;
volatile uint8_t pulsewidth = 125;
volatile uint16_t icr1_temp;

// ADC interrupt service routine
ISR(TIM1_OVF){
   icr1_temp = (uint16_t) ((uint32_t) ((uint32_t)period * 0x10000)/256);
   /*if(icr1_temp < 850){     //Без этого куска кода МК виснет при значении ICR1 < 850
    icr1_temp = 850;
   }*/
   ICR1 = icr1_temp;
   OCR1A = (uint16_t) ((uint32_t) ((uint32_t)pulsewidth * ICR1)/256); 
}

ISR(ADC_INT){
    if(ADMUX & (1<<MUX0)){
      pulsewidth = ADCH;                              //get ch 1
        ADMUX = (0<<REFS1)|(1<<REFS0)|(1<<ADLAR) | (1<<MUX1) | (0<<MUX0);   //set ch 0

    }else{
      period = ADCH;
      PORTD = period;                                 //get ch 0
        ADMUX = (0<<REFS1)|(1<<REFS0)|(1<<ADLAR) | (1<<MUX1) | (1<<MUX0);   //set ch 1
    }
   
   //ICR1 = (uint16_t) ((uint32_t) ((uint32_t)period * 0x10000)/256);         

   //OCR1A = (uint16_t) ((uint32_t) ((uint32_t)pulsewidth * ICR1)/256);

//delay_us(10);
// Start the AD conversion
ADCSRA|=(1<<ADSC);

}

void main(void)
 {
   // Write your code here

// Input/Output Ports initialization
// Port B initialization
// Function: Bit1=Out
DDRB = (1<<DDB1);
// State: Bit1=0 
PORTB = (0<<PORTB1);

// Port D initialization
// Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In 
DDRD=(1<<DDD7) | (1<<DDD6) | (1<<DDD5) | (1<<DDD4) | (1<<DDD3) | (1<<DDD2) | (1<<DDD1) | (1<<DDD0);

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: ...... kHz
// Mode: Ph. & fr. cor. PWM top=ICR1
// OC1A output: Non-Inverted PWM
// OC1B output: Disconnected
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer Period: 0 us
// Output Pulse(s):
// OC1A Period: 0 us
// Timer1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=(1<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (1<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);
TCNT1=0x00;
ICR1=0x0300;
OCR1A=0x00;
OCR1B=0x00;

// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (1<<TOIE1) | (0<<TOIE0);

// Analog Comparator: Off
ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);

// ADC initialization
// ADC Clock frequency: ..... kHz
// ADC Voltage Reference: AVCC pin
// Only the 8 most significant bits of
// the AD conversion result are used
ADMUX = (0<<REFS1) | (1<<REFS0) | (1<<ADLAR);
ADCSRA=(1<<ADEN) | (0<<ADSC) | (0<<ADFR) | (0<<ADIF) | (1<<ADIE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
SFIOR=(0<<ACME);

ADCSRA |= (1<<ADSC);   // Start the AD conversion

sei();



   while (1){
   }
 }
Реклама
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

а с какого хрена у тебя ICR1 может оказаться больше 255 (850), если период - однобайтная величина и не превышает 255?
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Реклама
Мучитель микросхем
Сообщения: 430
Зарегистрирован: Вс апр 18, 2021 15:43:55

Сообщение Kalisnik »

Я делаю ШИМ на 16-ти разрядном таймере Т1. Максимальная величина ICR1 = 0xffff (65 535).

Добавлено after 38 minutes 12 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
Вопрос снимается. Разобрался. Программа висела в прерывании по переполнению таймера - я туда вычисления с приведением типов поместил, которые очень долго выполнялись. В результате при выходе из подпрограммы уже висел флаг на повторное прерывание по переполнению таймера. А поскольку прерывание по переполнению таймера имеет больший приоритет чем у АЦП, то программа уходила в цикл бесконечного прерывания по переполнению таймера. :facepalm:

Добавлено after 3 minutes 34 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
Пипец мудрено... пока разберешься )) Моего кота на такое бы не хватило )
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

чтобы быстро работало, такие простые программы следует делать на ассемблере.
а язык Си хорош тогда, когда делаются очень большие программы, так как на Си писанины много меньше, чем на ассемблере.
вот у тебя на Си, и еще с приведением типов, писанины мало, а после компиляции кода до хрена - вот и выполняется медленно.
а также надо думать, что ты делаешь.
у тебя есть некоторая максимальная частота при которой время между переполнениями оказывается очень маленькое. и все вычисления нужно уложить в это минимальное время и еще оставить время для работы АЦП и главного цикла.
а чтобы быстро сделать работу в прерывании по переполнению, нужно вообще исключить любые вычисления в прерывании.
нужно, как я тебе говорил, в прерывании взять сохраненные значения периода и длительности импульса и записать их в регистры. тогда прерывание не будет мешать работать всему остальному
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Реклама
Эиком - электронные компоненты и радиодетали
Мучитель микросхем
Сообщения: 430
Зарегистрирован: Вс апр 18, 2021 15:43:55

Сообщение Kalisnik »

Starichok51 писал(а):а чтобы быстро сделать работу в прерывании по переполнению, нужно вообще исключить любые вычисления в прерывании.
Логично :) Как то я не думал что элементарные вычисления вроде деления и умножения отнимают так много времени. Наверно, это приведение типов так ресурсы пожирает?
Реклама
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

чем длиннее тип данных, тем дольше идут вычисления.
вот на это я забыл тебе ответить:
Kalisnik писал(а):Я делаю ШИМ на 16-ти разрядном таймере Т1. Максимальная величина ICR1 = 0xffff (65 535).
тебе это таймер нужен не для 16 бит, а для того, чтобы можно было записать любое число в качестве периода ШИМ.
а тебя период не может быть больше 255, так как используется только один байт из регистра ADCH.
и вот эта строка (да еще с приведением типов)
icr1_temp = (uint16_t) ((uint32_t) ((uint32_t)period * 0x10000)/256);
полная ахинея.
тебе нужно сделать присвоение
ICR1 = period;
и это всё, что нужно сделать.
и для длительности импульса достаточно такой записи
OCR1A = (uint16_t)(pulsewidth * ICR1)/256;
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Реклама
Мучитель микросхем
Сообщения: 430
Зарегистрирован: Вс апр 18, 2021 15:43:55

Сообщение Kalisnik »

ICR1 - это двухбайтный регистр. В режиме №8 Т1 он задает верхний предел счетного регистра (TCNT1). Переменная period содержит данные ADCH равные одному байту (255). Если мы просто присвоим ICR1 переменную period, то наш период будет равняться 255 тикам счетчика (макс.) из 65 535...

Добавлено after 11 minutes 14 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
Чтобы иметь возможность задавать период на всем протяжении счетного регистра, нам нужно этот регистр разделить на максимально возможное число регистра ADCH (65 535 / 255). Таким образом число 255 регистра ADCH является разрешающей способностью АЦП (периоду можно задать 255 различных временных величин).
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Kalisnik, вот так попробуйте
Спойлер

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

volatile uint16_t period;
volatile uint16_t pulsewidth;

ISR(TIMER1_OVF_vect){

	ICR1 = period;			

	OCR1A = pulsewidth;

}
в главном цикле

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

#include <util/atomic.h>

uint16_t period_temp, pulsewidth_temp;
uint16_t period_temp2, pulsewidth_temp2;

#define ADC_VREF_TYPE ((0<<REFS1) | (1<<REFS0) | (1<<ADLAR))


while (1)
      {
        ADMUX = ADC_VREF_TYPE | (0<<MUX0);//set ch 0 
		_delay_us(10);

		ADCSRA|=(1<<ADSC);
		while ((ADCSRA & (1<<ADIF))==0);
		ADCSRA|=(1<<ADIF);
		pulsewidth_temp = ADCH;

        ADMUX = ADC_VREF_TYPE | (1<<MUX0);//set ch 1
		_delay_us(10);

		ADCSRA|=(1<<ADSC);
		while ((ADCSRA & (1<<ADIF))==0);
		ADCSRA|=(1<<ADIF);
		period_temp = ADCH;		

	period_temp2 = (uint16_t) ((uint32_t) ((uint32_t)period_temp * 0x10000)/256);			

	pulsewidth_temp2 = (uint16_t) ((uint32_t) ((uint32_t)pulsewidth_temp * (uint32_t)period_temp2)/256);

		ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
	{	// блок кода с запрещенными прерываниями
		period = period_temp2;
		pulsewidth = pulsewidth_temp2;
	}

    }
Последний раз редактировалось Dimon456 Чт сен 30, 2021 10:14:14, всего редактировалось 1 раз.
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

Kalisnik, из темы я не понял, что тебе нужно большое число для периода. теперь мне стало понятно, что ты хочешь использовать весь диапазон 16 битов.
и не 255, а 256 у тебя будет шаг изменения регистра ICR1.
а для этого все равно не нужно ни умножать, ни делить.
для этого в ICR1H нужно записать period, а в ICR1L нужно записать НОЛЬ.
и тогда получится
ICR1H = period;
ICR1L = 0;
а для OCR1A, на первый взгляд, выражение (формулу) упростить не получится.

Добавлено after 9 minutes 1 second:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
и я полностью поддерживаю предложение от Dimon456 - убрать прерывание от ADC и обработку АЦП сделать в главном цикле.
а в прерывании по переполнению получится, как я ранее говорил, - только записать в регистры сосчитанные значения.
и долгая обработка вычислений не будет влиять на работу прерывания.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Starichok51 писал(а):ICR1H = period;
ICR1L = 0;
Да, вы правы, при 0x10000 он в ICR1L не будет писать, там будет 0.
При тактовой частоте 1МГц время нахождения в прерывании 16us, а это верхняя частота 62,5кГц, то есть ICR1H=0 ICR1L=8.
При 8МГц это уже получается, 62,5кГц, то есть ICR1H=0 ICR1L=64.

Смотря какая ему верхняя частота нужна.
При тактовой частоте 1МГц, ICR1H=1 ICR1L=0, 1953Гц
При тактовой частоте 1МГц, ICR1H=2 ICR1L=0, 651Гц
При тактовой частоте 8МГц, ICR1H=1 ICR1L=0, 15625Гц
При тактовой частоте 8МГц, ICR1H=2 ICR1L=0, 5208Гц

Я делал с тремя диапазонами, с возможностью менять 0x10000: 0x10000 0x01000 и 0x00100.
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

Dimon456 писал(а):При тактовой частоте 1МГц, ICR1H=1 ICR1L=0, 1953Гц
При тактовой частоте 1МГц, ICR1H=2 ICR1L=0, 651Гц
о чем ты думал, когда это писал?
при тактовой частоте 1МГц, ICR1H=1 ICR1L=1,953125 кГц.
при тактовой частоте 1МГц, ICR1H=2 ICR1L=0,9765625 кГц.
ну, и для 8 МГц ты тоже ерунду написал.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

[uquote="Kalisnik",url="/forum/viewtopic.php?p=4098552#p4098552"]элементарные вычисления вроде деления[/uquote]
на avr вообще нельзя делить ни на что, кроме степеней двойки. Нету аппаратного вычислителя. Только умножитель.
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Starichok51 писал(а):о чем ты думал, когда это писал?
Малость ошибся.

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

При тактовой частоте 1МГц, ICR1H=1 ICR1L=0,                       1953Гц
При тактовой частоте 1МГц, ICR1H=2 ICR1L=0,                       976Гц
При тактовой частоте 8МГц, ICR1H=1 ICR1L=0,                       15625Гц
При тактовой частоте 8МГц, ICR1H=2 ICR1L=0,                       7812Гц
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

для длинных переменных на умножение тоже тратится не мало времени, но гораздо меньше, чем на деление.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Мучитель микросхем
Сообщения: 430
Зарегистрирован: Вс апр 18, 2021 15:43:55

Сообщение Kalisnik »

Starichok51 писал(а):и не 255, а 256 у тебя будет шаг изменения регистра ICR1.
Почему 256?
65 535 / 255 = 257
И 255 различных положений ICR1 (0 не считаем, период не может быть нулевым).
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

на формулу свою посмотри - там деление на 256, а не на 255.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Мучитель микросхем
Сообщения: 430
Зарегистрирован: Вс апр 18, 2021 15:43:55

Сообщение Kalisnik »

Dimon456 писал(а):и тогда получится
ICR1H = period;
ICR1L = 0;
Это точно подмечено. Я об этом даже не подумал.

Добавлено after 2 minutes 19 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки
[uquote="Starichok51",url="/forum/viewtopic.php?p=4098653#p4098653"]на формулу свою посмотри[/uquote]
Это не моя формула. Взял код у Dimon456 :)

Добавлено after 8 minutes 47 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
Ага... с шагом 257 уже не получится писать в регистр ICR1L ноль. Ну, можно сделать шаг 256 - большой разницы не будет. 256 * 255 = 65 280 - почти верхний предел.
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

опять ты в своих "трех соснах" запутался.
у тебя 255 шагов, не считая ноль.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Мучитель микросхем
Сообщения: 430
Зарегистрирован: Вс апр 18, 2021 15:43:55

Сообщение Kalisnik »

я имел в виду "длину шага"

Добавлено after 1 minute 14 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
Т.е. количество тиков в шаге
Модератор
Аватара пользователя
Сообщения: 19097
Зарегистрирован: Сб авг 14, 2010 15:05:51
Откуда: г. Озерск, Челябинская обл.

Сообщение Starichok51 »

режим №8 работает "туда и обратно".
когда ICR1 равно 256, количество тиков равно 512. то есть, в 2 раза больше, чем записано в регистре.
Мудрость приходит вместе с импотенцией...
Когда на русском форуме переходят на Вы, в реальной жизни начинают бить морду.
Ответить

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