Обсуждаем контроллеры компании Atmel.
Ответить

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

Ср сен 29, 2021 11:40:58

Новая проблема, теперь МК виснет при значении 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){
   }
 }

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

Ср сен 29, 2021 13:53:05

а с какого хрена у тебя ICR1 может оказаться больше 255 (850), если период - однобайтная величина и не превышает 255?

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

Ср сен 29, 2021 16:12:45

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

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

Добавлено after 3 minutes 34 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
Пипец мудрено... пока разберешься )) Моего кота на такое бы не хватило )

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

Ср сен 29, 2021 18:38:56

чтобы быстро работало, такие простые программы следует делать на ассемблере.
а язык Си хорош тогда, когда делаются очень большие программы, так как на Си писанины много меньше, чем на ассемблере.
вот у тебя на Си, и еще с приведением типов, писанины мало, а после компиляции кода до хрена - вот и выполняется медленно.
а также надо думать, что ты делаешь.
у тебя есть некоторая максимальная частота при которой время между переполнениями оказывается очень маленькое. и все вычисления нужно уложить в это минимальное время и еще оставить время для работы АЦП и главного цикла.
а чтобы быстро сделать работу в прерывании по переполнению, нужно вообще исключить любые вычисления в прерывании.
нужно, как я тебе говорил, в прерывании взять сохраненные значения периода и длительности импульса и записать их в регистры. тогда прерывание не будет мешать работать всему остальному

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

Ср сен 29, 2021 19:03:59

Starichok51 писал(а):а чтобы быстро сделать работу в прерывании по переполнению, нужно вообще исключить любые вычисления в прерывании.

Логично :) Как то я не думал что элементарные вычисления вроде деления и умножения отнимают так много времени. Наверно, это приведение типов так ресурсы пожирает?

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

Ср сен 29, 2021 19:22:42

чем длиннее тип данных, тем дольше идут вычисления.
вот на это я забыл тебе ответить:
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;

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

Ср сен 29, 2021 20:18:08

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 различных временных величин).

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

Ср сен 29, 2021 20:46:02

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 раз.

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

Ср сен 29, 2021 21:05:37

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

Добавлено after 9 minutes 1 second:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
и я полностью поддерживаю предложение от Dimon456 - убрать прерывание от ADC и обработку АЦП сделать в главном цикле.
а в прерывании по переполнению получится, как я ранее говорил, - только записать в регистры сосчитанные значения.
и долгая обработка вычислений не будет влиять на работу прерывания.

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

Ср сен 29, 2021 21:19:42

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.

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

Ср сен 29, 2021 21:35:45

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 МГц ты тоже ерунду написал.

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

Ср сен 29, 2021 21:38:18

элементарные вычисления вроде деления

на avr вообще нельзя делить ни на что, кроме степеней двойки. Нету аппаратного вычислителя. Только умножитель.

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

Ср сен 29, 2021 22:06:58

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Гц

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

Ср сен 29, 2021 22:08:30

для длинных переменных на умножение тоже тратится не мало времени, но гораздо меньше, чем на деление.

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

Ср сен 29, 2021 22:21:30

Starichok51 писал(а):и не 255, а 256 у тебя будет шаг изменения регистра ICR1.

Почему 256?
65 535 / 255 = 257
И 255 различных положений ICR1 (0 не считаем, период не может быть нулевым).

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

Ср сен 29, 2021 22:56:28

на формулу свою посмотри - там деление на 256, а не на 255.

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

Ср сен 29, 2021 23:09:52

Dimon456 писал(а):и тогда получится
ICR1H = period;
ICR1L = 0;

Это точно подмечено. Я об этом даже не подумал.

Добавлено after 2 minutes 19 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки
на формулу свою посмотри

Это не моя формула. Взял код у Dimon456 :)

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

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

Ср сен 29, 2021 23:31:57

опять ты в своих "трех соснах" запутался.
у тебя 255 шагов, не считая ноль.

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

Ср сен 29, 2021 23:34:51

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

Добавлено after 1 minute 14 seconds:
Re: Atmega8, ШИМ - низкий уровень на выводе после остановки ШИМ.
Т.е. количество тиков в шаге

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

Чт сен 30, 2021 08:33:14

режим №8 работает "туда и обратно".
когда ICR1 равно 256, количество тиков равно 512. то есть, в 2 раза больше, чем записано в регистре.
Ответить