Простой ШИМ на ATTiny13.Регулируем всё

Искал схему ШИМ на дискретных элементах для регулировки маленького паяльника, находились схемы на таймере 555, к561ла7, к561лн2, на мультивибраторе из транзисторов
Собрав несколько из них – ни одна меня не устроила – был слишком крутой спад\подъем ступеньками сопротивления при вращении ручки переменного резистора – от 2х кОМ сразу подскакивало к 7кОМ следовательно при этом к примеру включенный на исток полевого транзистора компьютерный вентилятор со скорости 20 процентов сразу начинал вращаться на 90-100%, если не вращать переменник с прецизионной точностью и\или с замером сопротивления при вращении.
Была найдена схема ШИМ на ATTiny13 на странице  – cxem.net/master/61.php ,
к которой я отнесся сначала скептически и зря, зря, потому что с ней обвязки нужно гораздо меньше по сравнению с дискретными схемами, микросхемка маленькая и дешевая, ШИМ точный и ножек всего 8, как и у таймера NE\LM555.

Наглядная схема(принципиальная схема имеется на вышеприведенном сайте):

Распиновка(pinout) Atmel (Microchip)ATTiny13A:

 

 

Светодиоды лучше брать с тусклым свечением, разные  яркие цвета могут раздражать, особенно ярко светится синий светодиод.
Можно обойтись и без светодиодов(следовательно и еще без трёх резисторов) они просто нужны для индикации и отображения режима работы.

Также можно обойтись и без линейного стабилизатора напряжения LM7805(КРЕН5), если регулируемая нагрузка питается от 5-ти вольт.
Для стабильности напряжения можно добавить керамические конденсаторы (на изображении в салатовом квадрате) – 0,33 микроФарад (334) на вход 7805, и 0,1 микрофарад(104) на выход 7805.

Нагружаемая мощность  зависит только от полевого (MOSFET) транзистора.

По случаю у меня как раз завалялось уже ненужное мне реле времени, где оказался тот самый микроконтроллер attiny13, к тому же на плате уже были выводы под пайку для прошивки микросхемы.
Почитав комментарии под схемой на той самой странице, увидел несколько комментариев о ошибке – надо вначале держать кнопку 30 секунд, чтобы ШИМ запустился.По моему это ну очень долго.Так как исходники прилагались- решил исправить ошибку и добавить индикацию работы светодиодами понагляднее.Исходники, к моему сожалению оказались на BascomAVR.Пришлось его скачать, открыть исходник.
Исправив ошибку с ожиданием в 30 секунд- решил проверить и залить прошивку.
Но прошивка не захотела литься, подумав что это ошибка компилятора BascomAVR было решено написать свой код для ATTiny13 на Си в Atmel Studio 7, конечно с сохранением оригинальной схемотехники, чтобы было можно только лишь залить прошивку и ничего не переделывать на печатке.
Написал тестовый код в Atmel Studio, скомпилировал прошивку, заливаю в attiny13 – опять ошибка:
mismatch 0x000000
Ошибка оказалась не в средах разработки, а в программе для прошивки мк, конкретно в моем случае в  eXtreme Burner AVR, для того, чтобы исправить данную ошибку необходимо открыть файл C:\Program Files\eXtreme Burner – AVR\Data\chips.xml
Найти ATTiny13 и между тегами <PAGE>64</PAGE>
Вместо 64 написать 32 – после этого ATTiny13 начал шиться без проблем.

Спустя несколько дней программа была написана.

Для прошивки ATTiny требуется – USB ASP Программатор микроконтроллеров ATmega AVR

Смотрите также:

Как прошить микроконтроллер ATmega, AVR

Эмуляция AVR в Proteus, микроконтроллеры в Proteus

Как написать код для AVR, программирование микроконтроллеров Atmel AVR на Си

 

Что изменено и добавлено:
+Не надо жать кнопку на протяжении 30 секунд
+ Добавлено 8 значений ШИМ вместо 7
+ Добавлена индикация включения
+ Сделана наглядная индикация режима ШИМ
+ Сделано Автосохранение значения ШИМ(по умолчанию выключено)

Индикация включения – при включении очень быстро и реверсивно перельются все три светодиода.
Переключение режимов осуществляется нажатием на кнопку, действует циклически.

Режимы:
0 – Все светодиоды выключены,Значение ШИМ – 0, 0%
1 – Моргает светодиод 1, ШИМ – 32, 12%
2 – Моргает светодиод 2,ШИМ – 64, 25%
3 – Моргает светодиод 3,ШИМ – 96, 37.6%
4 – Все светодиоды переливаются, ШИМ – 128, 50%
5 – Горит светодиод 1, ШИМ – 160, 62.7%
6 – Горит светодиод 2, ШИМ – 192, 75.2%
7 – Горит светодиод 3, ШИМ – 224, 87.8%
8 – Все светодиоды моргают, ШИМ – 255, 100%

Для включения автосохранения значения ШИМ необходимо удержать кнопку в течении 3х секунд, для отключения – осуществить тоже самое.
При этом при включении автосохранения на 1,5 секунды загорится светодиод 1.
При отключении – на 1,5 секунды загорится светодиод 3.Удерживать кнопку можно в любом режиме, но лучше это делать в режиме 0- так будет нагляднее.

Учтите, что при включенном автосохранении каждый раз при нажатии на кнопку записываются данные в EEPROM, ресурс записи EEPROM в Atmel AVR – 100 000.

 

Необходимо поставить фьюз на работу от внутреннего тактового генератора на 9,6 Мгц:

Т.к. я пользуюсь eXtreme Burner AVR то во вкладке Fuse\Bits записываю такие байты вместо выставления галок(в других программах-прошивальщиках галки):

Младший байт(Low Byte\Fuse) – 7A

Старший байт (High Byte\Fuse) – EB

Для того, чтобы знать какие галки ставить в других программах, чтобы микроконтроллер работал на частоте 9.6Мгц , можно использовать данный сайт:

homes-smart.ru/fusecalc/?prog=avrstudio&part=ATtiny13A

Слева вверху, где написано Байты конфигурации вводим  – 7A в окошечко LOW

и EB в окошечко HIGH – получаем указание на то, где следует поставить галки.

(В чём отличие ATTiny13 от ATTiny13A?

Tiny13A – это более новый и улучшенный микроконтроллер от  Atmel

Ранее выпускались два варианта Тини13 – с обычным(ATTiny13, работает от 2.7 вольт) и пониженным(ATTiny13V, работает от 1.8 вольт) питанием.

При этом первый вариант работает на частоте до 20 Мгц, второй – до 10Мгц.

С выходом Тини13А убрали разделение мк по питанию, Тини13А работает и от 1.8 вольт, при этом при пониженном низковольтном питании также невозможно заставить работать микроконтроллер на высокой частоте.)

Схема и печатная плата имеется на приведенном выше сайте(в начале статьи).

 

Прошивка в формате HEX:

SolderPWM

Прошивка с более высокой частотой(Не тестировалась на реальной схеме!):

PWM_HF

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

/*
/*
 * SolderPWM.c
 *
 * Created: 05.11.2017 23:33:14
 * Author LampCORE.ru: 
 */ 
 
 
#define F_CPU 9600000UL //частота процессора 9,6 Мгц
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/eeprom.h>
 
//макросы для включения, выключения светодиодов
//низкий уровень - на ножке 0 вольт, высокий уровень - на ножке 5 вольт
#define LED1_OFF PORTB &= ~(1<<PB4); //Низкий уровень ножки PB4 
#define LED2_OFF PORTB &= ~(1<<PB3); //Низкий уровень ножки PB3
#define LED3_OFF PORTB &= ~(1<<PB2); //Низкий уровень ножки PB2
 
#define LED1_ON PORTB |= (1<<PB4);  //Высокий уровень ножки PB4
#define LED2_ON PORTB |= (1<<PB3);  //Высокий уровень ножки PB3
#define LED3_ON PORTB |= (1<<PB2); //Высокий уровень ножки PB2
//Указатели для EEPROM
uint8_t autosave_p EEMEM; uint8_t level_p EEMEM;
//Переменная для выбора режима ШИМ
uint8_t level=0;
//volatile - чтобы компилятор не трогал эти переменные и не оптимизировал
//Счетчики в прерывании
//для мигания 
volatile uint8_t count=0;
//для переливания 3х светодиодов
volatile uint8_t count2=0;
//счетчик удержания кнопки 
volatile uint8_t i=0;
//переменная для события был_клик
volatile uint8_t wasclick=0;
//36 переполнений (36 раз происходит событие TCNT0>255 ) = 1 секунда
// Прерывание по совпадению счетчика таймера с OCR0A
// 9 600 000 Гц/Предделитель 1024 / 1000 = 9 375 Гц в секунду/255=36 прерываний 
//в секунду
ISR (TIM0_COMPA_vect)
{
 
//инкремент счетчиков, две переменные, чтобы режимы 
//светодиодов мигания и переливания не зависили друг от друга
count++;
//если больше пол секунды
if(count>18){count=0;}
 
	count2++;
	//если больше секунды
	if(count2>36){count2=0;}
 
}
 
 
//функция отключить все светодиоды
void off_all_led()
{
	LED1_OFF;LED2_OFF;LED3_OFF;
}
 
 
 
 
int main(void) {
 
// Настраиваем порты ввода/вывода	
DDRB |= 1<<PB4;//Ножка PB4 как выход
DDRB |= 1<<PB3;//Ножка PB3 как выход
DDRB |= 1<<PB2;//Ножка PB2 как выход
 
 
DDRB |= 0<<PB1;//Ножка PB1 как вход(кнопка)
PORTB |= (1 << PB1);//Включаем подтягивающий Pull-UP резистор для ножки 
//PB1(вход-кнопка)(высокий уровень(+5Вольт))
 
 
DDRB   |= (1 << PB0);    //Ножка PB0 как выход(ШИМ)
TCCR0A = (1 << COM0A1) | (1 << WGM00);  //выбор ШИМ  с фазовой коррекцией
TCCR0B = 0x05; //Предделитель - 1024 и старт таймера
TCNT0 = 0;     // Сброс счетчика прерываний(0-255)
OCR0A=0;       //Выбор Значения ШИМ
 
 TIMSK0=0x04;//Разрешить выполнение прерываний по совпадению в OCR0A	 		
 sei();// Разрешить глобальные прерывания
 
 
	//Индикация включения, быстрое переливание светодиодов с инвертированием
	LED3_ON;
	_delay_ms(45);
	LED3_OFF;
 
	LED2_ON;
	_delay_ms(45);
	LED2_OFF;
 
	LED1_ON;
	_delay_ms(45);
	LED1_OFF;
 
	LED2_ON;
	_delay_ms(45);
	LED2_OFF;
 
	LED3_ON;
	_delay_ms(45);
	LED3_OFF;
 
 
	//переменная для хранения значения автосохранения включено\выключено
		uint8_t autosave;
		//считать значение автосохранения с EEPROM по адресу в &autosave_p
		autosave=eeprom_read_byte(&autosave_p);
 
 
	//если сохранение включено то режим ШИМ равен значению из EEPROM 
	if (autosave==1)
	{
		level=eeprom_read_byte(&level_p);
		//Проследовать сразу на метку handler_button, где 
		//сразу инициируется режим, считанные из EEPROM
		goto handler_button;
	}
 
 
 
 
	//Бесконечный цикл
	while(1)
	 {
 
 
 
 //Если на PB1 низкий уровень(если кнопка нажата)
 if( ! (PINB & (1 << PB1))) { 
//Событие был_клик произошло 
wasclick=1;
//инкремент счетчика нажатия кнопки до i=255
if (i!=255){ _delay_ms(83); i++; //если прошло 3 и более секунд 
if (i>=36)
	{
		//Событиея был_клик НЕ было
		wasclick=0;
 
				//если автосохранение включено - отключить, записать
// это в EEPROM
		if (autosave==1)
		{
			eeprom_write_byte(&autosave_p,0);
			autosave=0;
		}
		//если автосохранение выключено - включить, записать в EEPROM
		else
		{
			eeprom_write_byte(&autosave_p,1);
		autosave=1;
		}
 
 
		//если автосохранение включено включить светодиод 1 на 1,5 секунды
		if (autosave==1)
		{	
			LED1_ON;
			_delay_ms(1500);
			LED1_OFF;
			//перейти сразу к обработке переменной level
			goto handler_button;
		}	
 
		else
		//иначе, если автосохранение выключено включить светодиод 3 на
//1,5 секунды
		{
	      LED3_ON
	      _delay_ms(1500);
	      LED3_OFF;
		  //перейти сразу к обработке переменной level
		  goto handler_button;
 
		}
 
 
 
	i=0;//сброс счетчика после долгого нажатия	
 
	 //перейти сразу к обработке переменной level
	goto handler_button;
 
	}//i>=36
 
 
 }//i!=255
 
 
 
}//! (PINB & (1 << PB1))
 
 
 
// Выполнять только, если кнопка отпущена т.е. выполняется, только, если wasclick=1
//(событие был_клик произошло)
if  ( (PINB & (1 << PB1))&&wasclick==1) { //события был_клик не было wasclick=0;
_delay_ms(83); 
//Точные числа перескакивают, в узкий диапазон попасть трудно, поэтому от 2х до 12,
// 2*83+83=249 миллисекунд
//если кнопка была нажата (+83миллисекунды пауза внутри условия) 83*2 миллисекунд
if (i>=2&&i<=12) 
{ 
// повысить режим
level++; 
//если режим превышает 7 сделать режим 0
if(level>8){level=0;}
 
			   //если включено автосохранение записать в EEPROM значение
// режима
			   	if (autosave==1)
			   	{
				   	eeprom_write_byte(&level_p,level);
			   	}
 
 
		   //метка обработки переменной level(режимов)
		handler_button:   	   	
	   	switch(level)
	   	{
			   //каждому значению level - свое значение ШИМ и режим 
//светодиодов
		   	case 0:OCR0A=0;off_all_led();break;
		   	case 1:OCR0A=32 ;off_all_led(); break;
		   	case 2:OCR0A=64;off_all_led()  ;break;
		   	case 3:OCR0A=96;off_all_led()   ;break;
 
 
		   //Если быстро нажать кнопку count2 не сбросится и какой-либо
                  // светодиод будет гореть
		  //некоторое время вместо того, чтобы погаснуть - переливания не
                  // будет
		  //принудительно сбросим count2
		   	case 4:OCR0A=128;off_all_led();count2=0;break;
 
		   	case 5:OCR0A=160;off_all_led() ;
		   	LED1_ON;
		   	break;
 
		   	case 6:OCR0A=192;off_all_led()   ;
		   	LED1_ON;LED2_ON;
		   	break;
 
		   	case 7:OCR0A=224;off_all_led() ;
		   	LED1_ON;LED2_ON;LED3_ON;
		   	break;
 
 
		   	case 8:OCR0A=255;off_all_led();break;
 
 
	   	}//switch
 
	i=0;//сброс счетчика кнопки
   }//i>=2
 
 
 
 
}//release отпущено
 
 
 
 
	//Мерцания светодиодов		
	//Каждому значению ШИМ - свой режим светодиодов
	 switch(level)
	 {
	 case 0:;break;
	 case 1:	
        //count прибавляется на 9 за пол секунды
       if(count>=0&&count<9){LED1_ON;} if(count>9&&count<=18){LED1_OFF;} ;
        break; 
 
case 2: 
//
if(count>=0&&count<9){LED2_ON;} 
if(count>9&&count<=18){LED2_OFF;} ;
break; 
case 3: 
// 
if(count>=0&&count<9){LED3_ON;} if(count>9&&count<=18){LED3_OFF;} ;
break; 
case 4: 
//переливания, свой счетчик count2
if(count2>=0&&count2<6)
{LED3_OFF;LED2_OFF;LED1_ON} if(count2>6&&count2<=12){LED1_OFF;} 
if(count2>=12&&count2<18){LED1_OFF;LED3_OFF;LED2_ON} 
if(count2>18&&count2<=24){LED2_OFF;} 
if(count2>=24&&count2<30){LED2_OFF;LED1_OFF;LED3_ON} 
if(count2>30&&count2<=36){LED3_OFF;} ;break; 
case 5: ;break; 
case 6:;break; 
case 7:;break; 
case 8: if(count>=0&&count<9){LED1_ON;LED2_ON;LED3_ON;}
if(count>9&&count<=18){LED1_OFF;LED2_OFF;LED3_OFF;}
	;break;
 
	 }
 
 
 
	 }//while
 
 
}//main