ШИМ на Attiny13 управляемый напряжением или аналоговым сигналом

Дело было вечером — делать было нечего, ай думаю забацаю ШИМ который будет управляться сигналом с АЦП.Для создания сего чуда будем использовать Attiny13 — у меня их куча завалялась. Юзать будем апартный ШИМ. Причём один выход назначим инвертированный, а другой прямой. Ещё подключим кнопку для того чтобы менять частоту таймера ну и тем самым несущую  частоту ШИМ.

Вот такая модель вышла в Proteus

pwm

Принципиальная схема не собиралась в железе, но работать должна — тут собственно схемы той — резисторы и мк и транзистор на выход поставить, к примеру так:

pwm13

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

Пред-делитель  = 1.pwm 1

Пред-делитель  = 2.pwm 2

Пред-делитель  = 3.pwm 3

Пред-делитель  = 4.pwm 4

Пред-делитель  = 5.pwm 5

Применений много — от регулятора мощности до регулятора света или напряжения.

Исходный код программы:

#include <tiny13.h>
#include <delay.h>
#define ADC_VREF_TYPE 0x00
  unsigned int pwm = 0;
  float pwm_f=0;
  unsigned char pwm_val = 0;   
  eeprom unsigned char trc[2];
// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
// Delay needed for the stabilization of the ADC input voltage
delay_us(10);
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}

void main(void)
{
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Func5=In Func4=In Func3=In Func2=In Func1=Out Func0=Out 
// State5=T State4=T State3=T State2=T State1=0 State0=0 
PORTB=0x00;
DDRB=0x03;
PORTB.4=1;
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: Timer 0 Stopped
// Mode: Phase correct PWM top=0xFF
// OC0B output: Non-Inverted PWM
// OC0A output: инвертрованое значение
TCCR0A=0xB1;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x00;

// ADC initialization
// ADC Clock frequency: 76,563 kHz
// ADC Bandgap Voltage Reference: Off
// ADC Auto Trigger Source: ADC Stopped
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
DIDR0&=0x03;
DIDR0|=0x00;
ADMUX=ADC_VREF_TYPE & 0xff;
ADCSRA=0x87;
 if(PINB.4==0){delay_ms(10);while(!PINB.4){;}; TCCR0B=3; trc[0] = 0;} //если зажали кнопку при включении
 //то сбрасываем сохранения 
 if(trc[0]==1){TCCR0B = trc[1];} //проверяем сохранённое значение
 else{trc[1]=3; TCCR0B = trc[1];} //востанавливаем
while (1)
 { 
 pwm = (int)read_adc(1); //считываем значение АЦП
 pwm_f =(int) pwm/4; //делим его на 4 и берём только целую часть
 pwm_val=(char)pwm_f; //преобразование типов
 OCR0A = (char) pwm_val; //записываем значение в регистр А
 OCR0B = (char) pwm_val; //записываем значение в регистр В
 delay_ms(1);
 
 if(PINB.4==0){delay_ms(10);while(!PINB.4){;}; TCCR0B++; trc[1] = TCCR0B; trc[0]=1;} //изменяем частоту ШИМ
 if(TCCR0B>=6){TCCR0B=1;}
 }
}

07.04.17 FUSE


Скачать проект ШИМ на Attiny13 управляемый напряжением или аналоговым сигналом Скачали 7168 раз

ШИМ на Attiny13 управляемый напряжением или аналоговым сигналом: 50 комментариев

  1. Спасибо автору за отличный пример ШИМ+АЦП очень помогло при разработке регулятора оборотов для двигателя постоянным токо с управлением от потенциометра.

  2. Здравствуйте.!Не смогли бы Вы помочь?В программировании не разбираюсь.Нужно на Аттини13 шим сигнал на выходе получить , импульс 50мкс , частота меняется по желанию от кнопки -1гц , 5гц , 10гц , 50гц.
    Спасибо

  3. Здравствуйте. Подскажите, как сделать задержку изменения ШИМ сигнала при кратковременном изменении входящего аналогового сигнала? Хочу применить это устройство для регулировки яркости светодиодов от цифрового датчика освещенности. Что бы например при проезде под мостом, или при езде в темное время суток под фонарями освещения яркость не мигала. Спасибо

  4. Прошу Вас проконсультировать: необходимо, чтобы при подаче питания, МК включался сразу на несущую частоту 18-20 кГц. Можно это сделать без изменения
    исходного кода? А если нет, то как изменить?
    Заранее благодарю.

  5. Добрый день.
    Подcкажите , как сделать так чтобы шим работал только, когда напряжение на аналоговом входе меняется от 2,97 до 4,18 вольт, при меньшем чем 2,97 вольт низкий логический уровень на выходе, при напряжении более 4,18 вольт высокий уровень. Сам только начинаю изучать программирование, самостоятельно не могу разобраться.

  6. Добрый день. Объясните пожалуйста для чего в этой части кода
    adc = (int)read_adc(1); //считываем значение АЦП
    adc_f =(int) adc/4; //делим его на 4 и берём только целую часть

    Вы делите считанное значение на 4?

  7. Подскажите пожалуйста, не могу разобрать ошибку:

    adc = (int)read_adc(1); //считываем значение АЦП
    adc_f =(int) adc/4; //делим его на 4 и берём только целую часть
    adc_in=(char)adc_f; //преобразование типов

    if (adc_in>=0 && 18 && 20 && <=23) Error:invalid expression
    {OCR2=14;}
    ……..

    Когда писал так же под тини13 — не было никаких ошибок

    1. Так нельзя делать

      if (adc_in>=0 && 18 && 20 && < =23)

      нельзя!
      Если надо сравнить то:

      if (adc_in>=0 && adc_in< =23)
      или if (adc_in==0||adc_in==18||adc_in==20||adc_in==23)
      

      ну и все в таком духе, смотря что нужно...
      Сам компилятор вам подсказует что у вас ошибка в выражении.
      ____________________________________________________________
      Чтобы корректно вставить код используйте теги: КОД

      1. Спасибо за помощь. Вот так было написано:

        adc = (int)read_adc(1); //считываем значение АЦП
        adc_f =(int) adc/4; //делим его на 4 и берём только целую часть
        adc_in=(char)adc_f; //преобразование типов

          1. Для Atmega8. В моем случає памяти Attiny13 мало…
            Я просто не могу понять, в чем ошибка кода. В первом сравнении убрал && оставил просто adc<18 и компилятор не ругается….
            Спасибо

  8. Добрый день. Подскажите, как изменить или добавить код для включения — отключения шим кнопкой? Как выключателем, нажата — есть ШИМ на выходе, отпущена — на выходах вместо ШИМ — 0. Спасибо.

    1. Шимом управляют регистры:
      TCCR0A=0xB1;
      TCCR0B=0x03;
      Соответственно если сделать так:
      TCCR0A=0x00;
      TCCR0B=0x00;
      Шим формироваться не будет — только выход шыма надо дополнительно после этого в ноль сбросить.
      Вот и все, далее думаю разберётесь.

      1. Благодарю. Как дополнительно в ноль сбросить не понял (в ноль само собой сбрасывается), но кнопка заработала так, как я хотел. Как-то так:
        if(PINB.5==0)
        {
        TCCR0A=0x00;
        }
        if(PINB.5==1)
        {
        TCCR0A=0xB1;
        }
        Кстати, поясните, как в ноль сбрасывать? Где-то что-то я не понимаю.

  9. Добрый день.
    Подкажите, в программировании не селен, но есть необходимость подкорректировать данный проект изменения в следуюющем:
    1. Убрать кнопку.
    2. Оставить несущую частоту только 23кГц
    Буду признателен. Спасибо.

  10. Хочу спросить автора, а что если к выходу подключить высоковольтный полевик типа IRF 730 и выпрямленное сетевое напряжение подать на бесхозный транс от старого имульсного БП? Будет работать? ))

  11. Всім привіт!
    Шановний Автор, дякую за статтю.
    І, звичайно ж, просьба.
    Прокоментуйте, буьд-ласка, наступні стрічки:

    unsigned int pwm = 0;
    float pwm_f=0;
    unsigned char pwm_val = 0;
    eeprom unsigned char trc[2];

    Дякую!

    1. Вообще это все инициализация переменных — их объявление в шапке программы…
      unsigned int pwm = 0; // шим целое число в которое считывается код АЦП
      float pwm_f=0; // шим преобразованый в число с плавающей запятой
      unsigned char pwm_val = 0; // значение шим преобразованое в код для записи в регистры
      eeprom unsigned char trc[2]; // массив в памяти для хранения режима работы шим — частоты.

  12. Добрый день Артем,
    подскажите пожалуйста, управляю ШИМом светодиод, и при значении на регистре OCR0A или B =0, светодиод не тухнет, яркость конечно у него на минимуме, но хочется чтоб он был выключен. Посмотрел на выходах тиньки, при значениях в ноль, есть импульсы, равные установленному значению clock value. Как с этим бороться? выключать таймер? подскажите

  13. Спасибо за статью! Хочу сделать на основе вашей схемы фонарик стабилизированый по току (литий 2.8…4.2в). Опорное напряжение выставил от внутреннего опорника(1.1в), место переменного резистора цепляемся на шунт, через который подключена схема светодиода. Инвертированый выход идет на затвор транзистора светодиода.
    Подскажите пожалуйста, как регулировать максимальный уровень тока на светодиоде кнопкой? Например нажал кнопу — стабилизирует на 20 мА, еще нажал — на 50 мА, еще — на 100 мА с сохранением последнего значения в память.
    Что отвечает за максимальный уровень?
    Если можна, расскажите подробнее, так как я только знакомлюсь с AVR.
    Заранее благодарен.

    1. Имхо такой стабилизатор можно попробывать сделать) Если использовать АЦП то тут все зависит от шунта. Например если у вас на шунте при токе 100мА падение напряжения 1.1В(тобишь равно опорному) то АЦП будет давать значение 1024 что максимально в данном случае — значит и ток 100мА будет максимальный. Вообщем нужно заранее определится с максимальным током, но сильно его не загибать вверх так как разрешающая способность АЦП тоже не бесконечна. Тут будет действовать такое ограничение — чем выше максимальный ток тем меньше точность установки малых значений. Как регулировать это все кнопкой думаю догадаетесь)

      1. Регулировать мне нужно не шунтом, а программно.
        Кажется нашел решение:
        if(OCR0B<=126) {OCR0B=127;}

        1. ШУНТ определит максимальный ток, а регулировка естественно программная…Не совсем ясно что вы добьётесь этой строчкой) — она ничего не делают кроме проверки регистра ШИМ…А вам нужно измерить напряжение на шунте — сравнить его с эталоном(установленным током) и если ток ниже то прибавлять значение регистра ШИМ, а если же больше то убавлять — примерно так.

  14. Добрый день Артем ! Хочу обратиться к вам с просьбой. В моем устройстве требуется на выходе шим 2,4 Гц. Вы могли бы изменить программу для такого случая. Мои поиски в интернете безрезультатны, понимаю что готовый шим на такую частоту не найду.

      1. Именно 2,4 Гц. Сигнал подается на вход CPU устройства, к которому я пытаюсь подцепиться, и устойчиво воспринимает ШИМ в пределах — от 2,35 Гц до 2,45 Гц. Эти значения я проэкспериментировал на ШИМе, собранном «на коленке» на NE555. Ключевой момент — частота ШИМа не должна выходить за эти рамки как при -30 мороза, так и +30 летом (в авто используется). Соответственно если брать кварц, делить частоту до такого значения, собирать АЦП, компараторы и всё на рассыпухе, сами понимаете как это громоздко. Вот и копаю интернет в поисках чего-то готового на МК или PIC. Бесполезно.

  15. Здравствуйте!
    А на ASMe нет у вас такого ?
    Хочу повторить в железе . Для регулировки вентилятора с 4-pin PWM.
    Там частота около 20-25 кГц . И если чего то подправить, частоту например — АСМ хоть чуть-чуть знаю .

  16. Как у вас получилось
    TCCR0A=0xB1;
    TCCR0B=0x03?
    В CodeWizardAVR могу только добиться
    TCCR0A=0xB1;
    TCCR0B=0x00;
    Настройки таймера:
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    // Mode: Phase correct PWM top=0xFF
    // OC0A output: Non-Inverted PWM
    // OC0B output: Inverted PWM

    1. А что здесь удивительного??? Это то что генератор начального кода сгенерил — а значение потом вручную подставили и всё. Оно всёравно потом в программе кнопкой меняется.

  17. Не владею ни протеусом ни c для avr, поэтому проверить не смог, но объясните пожалуйста мне тупому, как может быть две функции main() в программе?

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *