Вот схема
а вот программа
Спойлер
Код: Выделить всё
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include <avr/sleep.h>
#include "button.h"
#define ZERO_CROSS PD2 //Вход импульсов ZERO-CROSS (INT0)
#define control_triac PD1 //Вывод на управляющий электрод симистора
#define v_change_speed 288 //Шаг регулировки изменения скорости
#define t_pulse_triac 50 //Длительность отпирающего импульса симистора 30 мкс (смотреть по ТУ для конкретного симистора)
#define SP_hi 9600 // максимальная скорость
#define SP_lo 1824 // миниимальная скорость
#define SP_m 4992 // средняя скорость
#define COM1 PD3
#define COM2 PD4
#define SEGA PB0
#define SEGB PB1
#define SEGC PB2
#define SEGD PB3
#define SEGE PB4
#define SEGF PB5
#define SEGG PB6
unsigned char segs_out = 0;
volatile unsigned char state_counter = 4;
volatile unsigned char output_change = 0;
unsigned char LCD_out[2] = {0, 0};
unsigned char count;
const unsigned char segment_table[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
unsigned long speed_lcd;
volatile unsigned int speed;
//************************ Функция инициализации ***********************
void initialization(void)
{
DDRB = 0x7F; //7 выходов сегмента
DDRD |= _BV(control_triac); //выход управляющего электрода
PORTD |= _BV(control_triac); //высокий уровень на управляющем выводе
DDRD &= ~_BV(ZERO_CROSS); //вход детектора нуля
PORTD |= _BV(ZERO_CROSS); //с подтягивающим резистором для питания транзистора оптрона
MCUCR |= _BV(ISC00); //внешнее прерывание 0 по любому изменению уровня
// GIMSK |= _BV(INT0); //разрешаем внешнее прерывание 0
// Инициализация Timer/Counter 0
TCCR0B |= (0 << CS02) | (1 << CS01) | (1 << CS00); // = 8МГц/64
TCNT0 = 0xC1;
TIMSK |= _BV(TOIE0)| _BV(OCIE1A); //разрешаем прерывание таймера 0 и таймера 1
}
// Следующая таблица имеет 10 записей для отображения символов 0-9, HEX-значения COM1-COM4
// для входов LCD A & B.
void LCD_print(char digit, unsigned char data)
{
if (digit == 1) LCD_out[0] = segment_table[data / 10];
if (digit == 2) LCD_out[1] = segment_table[data % 10];
}
void LCD_update(void)
{
output_change = 0;
// state_counter генерирует сигналы 2 выходов COM через PORTD,
// каждый имеет состояния HIGH и LOW.
switch (state_counter)
{
case 0:
//вывод десятков:
PORTD &= ~((1 << COM1) | (1 << COM2)); //вывод в режиме Hi-Z
DDRD &= ~((1 << COM1) | (1 << COM2)); //порт D пин 0 работает как ВХОД
segs_out = LCD_out[0];
PORTB = segs_out; //выводим в порт символ
DDRD |= (1 << COM1); //порт D пин 0 работает на ВЫХОД
DDRD &= ~(1 << COM2);
break;
case 1:
PORTD |= (1 << COM1); //
PORTB = segs_out ^ 0xFF;// инверсия выходов сегментов
break;
case 2:
//вывод единиц
PORTD &= ~((1 << COM1) | (1 << COM2)); //вывод в режиме Hi-Z
DDRD &= ~((1 << COM1) | (1 << COM2)); //порт D пин 0 работает как ВХОД
segs_out = LCD_out[1];
PORTB = segs_out;
DDRD |= (1 << COM2); //порт D пин 0 работает на ВЫХОД
DDRD &= ~(1 << COM1);
break;
case 3:
PORTD |= (1 << COM2); //
PORTB = segs_out ^ 0xFF; // инверсия выходов сегментов
break;
default:
DDRB = 0x00;
DDRD &= ~((1 << COM1) | (1 << COM2)); // COM1-COM2 отключены (входы)
}
}
//********************* Обработчик прерывания по переполнению Timer 0 ***************
ISR(TIMER0_OVF_vect)
{
// Перезагрузка значения для Timer 0
// Период Timer0 = 0.125 МГц = 8 МГц / 64.
// 2 мс = 8 мкс * 250
// 5 = 255-250
TCNT0 = 5;
state_counter++;
output_change = 1; // Это флаг для цикла main
if (state_counter > 3)
state_counter = 0;
BtnExe();
}
//********************* Обработчик внешнего прерывания 0 *****************************
ISR (INT0_vect) //По переднему/заднему фронтам импульса ZERO-CROSS
{
OCR1A = 10000 - speed; //Регистру сравнения присваиваем значение скорости
TCCR1B |= _BV(WGM12) | _BV(CS10); //Запускаем таймер 1 в режиме СТС с периодом счёта 1 мкс
}
//********************* Обработчик прерывания по сравнению Timer 1 *******************
ISR (TIMER1_COMPA_vect) //прерывание для формирования открывающего импульса симистора
{
PORTD &= ~_BV(control_triac); //Передний фронт отпирающего импульса симистора
_delay_us (t_pulse_triac); //Длительность отпирающего импульса
PORTD |= _BV(control_triac); //Задний фронт отпирающего импульса симистора
TCCR1B = TCNT1 = 0; //остановка и обнуление таймера 0
}
int main (void)
{
// Вызов функции инициализации (описание см. ниже):
initialization();
BtnInit();
speed = SP_lo; //скорость на середину диапазона
// Разрешить все прерывания:
sei();
while(1)
{
uint8_t button = BtnGet(); //читаем значение кнопок
if (!(BTN_PIN & BTN_POWER)) //если нажата кнопка POWER
{
GIMSK |= _BV(INT0); //разрешаем внешнее прерывание 0
TIMSK |= _BV(OCIE1A); //разрешаем прерывание таймера 1
}
if (BTN_PIN & BTN_POWER) //если отжата кнопка POWER
{
GIMSK &= ~_BV(INT0); //запрещаем внешнее прерывание 0
TCCR1B = TCNT1 = 0;
TIMSK &= ~_BV(OCIE1A); //запрещаем прерывание таймера 1
PORTD |= _BV(control_triac);
}
if (button == BTN_SHRT_UP) //если нажата кнопка +
{
speed += v_change_speed; //увеличиваем скорость с заданным шагом
if(speed > SP_hi) speed = SP_hi;//не выходя за пределы
}
if (button == BTN_SHRT_DOWN) //если нажата кнопка -
{
speed -= v_change_speed; //уменьшаем скорость заданным шагом
if(speed <= SP_lo) speed = SP_lo;//не выходя за пределы
}
speed_lcd = ((unsigned long)speed + 480) * 27 / 7776;
LCD_print(1, speed_lcd);
LCD_print(2, speed_lcd);
if (output_change)
{
LCD_update();
}
}
}
Вот такой регулятор
ЗЫ: И не понятно, в каком квадранте сейчас работает симистор. И в каком должен работать.






