281 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			281 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "zh_avr_ac_dimmer.h"
 | |
| // https://avr-start.ru/?p=3983
 | |
| static zh_avr_ac_dimmer_init_config_t _init_config = {0};
 | |
| volatile static bool _is_dimmer_work = false;
 | |
| volatile static uint8_t _dimmer_value = 0;
 | |
| volatile static uint8_t _dimmer_count = 0;
 | |
| static bool _is_initialized = false;
 | |
| volatile static bool _is_zero_crossing = false;
 | |
| 
 | |
| static avr_err_t _zh_avr_ac_dimmer_validate_config(const zh_avr_ac_dimmer_init_config_t *config);
 | |
| static void _zh_avr_ac_dimmer_gpio_init(void);
 | |
| static avr_err_t _zh_avr_ac_dimmer_timer_init(void);
 | |
| 
 | |
| avr_err_t zh_avr_ac_dimmer_init(const zh_avr_ac_dimmer_init_config_t *config)
 | |
| {
 | |
|     ZH_ERROR_CHECK(_is_initialized == false, AVR_ERR_INVALID_STATE);
 | |
|     avr_err_t err = _zh_avr_ac_dimmer_validate_config(config);
 | |
|     ZH_ERROR_CHECK(err == AVR_OK, err);
 | |
|     _init_config = *config;
 | |
|     cli();
 | |
|     _zh_avr_ac_dimmer_gpio_init();
 | |
|     err = _zh_avr_ac_dimmer_timer_init();
 | |
|     ZH_ERROR_CHECK(err == AVR_OK, err);
 | |
|     sei();
 | |
|     _is_initialized = true;
 | |
|     return AVR_OK;
 | |
| }
 | |
| 
 | |
| avr_err_t zh_avr_ac_dimmer_start(void)
 | |
| {
 | |
|     ZH_ERROR_CHECK(_is_initialized == true, AVR_ERR_NOT_FOUND);
 | |
|     _is_dimmer_work = true;
 | |
|     return AVR_OK;
 | |
| }
 | |
| 
 | |
| avr_err_t zh_avr_ac_dimmer_stop(void)
 | |
| {
 | |
|     ZH_ERROR_CHECK(_is_initialized == true, AVR_ERR_NOT_FOUND);
 | |
|     _is_dimmer_work = false;
 | |
|     return AVR_OK;
 | |
| }
 | |
| 
 | |
| avr_err_t zh_avr_ac_dimmer_set(uint8_t value)
 | |
| {
 | |
|     ZH_ERROR_CHECK(value <= 100, AVR_ERR_INVALID_ARG);
 | |
|     _dimmer_value = value;
 | |
|     return AVR_OK;
 | |
| }
 | |
| 
 | |
| void zh_avr_ac_dimmer_isr_handler(void)
 | |
| {
 | |
|     bool flag = false;
 | |
|     switch (_init_config.zero_cross_port)
 | |
|     {
 | |
|     case AVR_PORTB:
 | |
|         if ((PINB & (1 << _init_config.zero_cross_gpio)) == (1 << _init_config.zero_cross_gpio))
 | |
|         {
 | |
|             PORTB &= ~(1 << _init_config.triac_gpio);
 | |
|             flag = true;
 | |
|         }
 | |
|         break;
 | |
|     case AVR_PORTC:
 | |
|         if ((PINC & (1 << _init_config.zero_cross_gpio)) == (1 << _init_config.zero_cross_gpio))
 | |
|         {
 | |
|             PORTC &= ~(1 << _init_config.triac_gpio);
 | |
|             flag = true;
 | |
|         }
 | |
|         break;
 | |
|     case AVR_PORTD:
 | |
|         if (((PIND & (1 << _init_config.zero_cross_gpio)) == (1 << _init_config.zero_cross_gpio)) && _is_zero_crossing == false)
 | |
|         {
 | |
|             PORTD &= ~(1 << _init_config.triac_gpio);
 | |
|             // flag = true;
 | |
|             _is_zero_crossing = true;
 | |
|         }
 | |
|         if (((PIND & (1 << _init_config.zero_cross_gpio)) == 0) && _is_zero_crossing == true)
 | |
|         {
 | |
|             // PORTD &= ~(1 << _init_config.triac_gpio);
 | |
|             _is_zero_crossing = false;
 | |
|             flag = true;
 | |
|         }
 | |
|         break;
 | |
| 
 | |
|     default:
 | |
|         break;
 | |
|     }
 | |
|     if (_is_dimmer_work == true && flag == true)
 | |
|     {
 | |
|         if (_dimmer_value != 0)
 | |
|         {
 | |
|             if (_dimmer_value == 100)
 | |
|             {
 | |
|                 // cli();
 | |
|                 TIMSK0 &= ~(1 << OCIE0A);
 | |
|                 // sei();
 | |
|                 switch (_init_config.triac_port)
 | |
|                 {
 | |
|                 case AVR_PORTB:
 | |
|                     PORTB |= (1 << _init_config.triac_gpio);
 | |
|                     // _delay_us(ZH_TRIAC_TIME);
 | |
|                     // PORTB &= ~(1 << _init_config.triac_gpio);
 | |
|                     break;
 | |
|                 case AVR_PORTC:
 | |
|                     PORTC |= (1 << _init_config.triac_gpio);
 | |
|                     // _delay_us(ZH_TRIAC_TIME);
 | |
|                     // PORTC &= ~(1 << _init_config.triac_gpio);
 | |
|                 case AVR_PORTD:
 | |
|                     PORTD |= (1 << _init_config.triac_gpio);
 | |
|                     // _delay_us(10);
 | |
|                     // PORTD &= ~(1 << _init_config.triac_gpio);
 | |
|                     break;
 | |
|                 default:
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             else
 | |
|             {
 | |
|                 // cli();
 | |
|                 TCNT0 = 0;
 | |
|                 TIFR0 = (1 << OCF0A);
 | |
|                 TIMSK0 |= (1 << OCIE0A);
 | |
|                 // sei();
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| static avr_err_t _zh_avr_ac_dimmer_validate_config(const zh_avr_ac_dimmer_init_config_t *config)
 | |
| {
 | |
|     ZH_ERROR_CHECK(config != NULL, AVR_ERR_INVALID_ARG);
 | |
|     ZH_ERROR_CHECK((config->zero_cross_gpio >= 0 && config->zero_cross_gpio <= 7), AVR_ERR_INVALID_ARG);
 | |
|     ZH_ERROR_CHECK((config->triac_gpio >= 0 && config->triac_gpio <= 7), AVR_ERR_INVALID_ARG);
 | |
|     ZH_ERROR_CHECK(config->zero_cross_port >= AVR_PORTB && config->zero_cross_port <= AVR_PORTD, AVR_ERR_INVALID_ARG);
 | |
|     ZH_ERROR_CHECK(config->triac_port >= AVR_PORTB && config->triac_port <= AVR_PORTD, AVR_ERR_INVALID_ARG);
 | |
|     ZH_ERROR_CHECK(config->ac_dimmer_frequency >= ZH_50HZ && config->ac_dimmer_frequency <= ZH_400HZ, AVR_ERR_INVALID_ARG);
 | |
|     return AVR_OK;
 | |
| }
 | |
| 
 | |
| static void _zh_avr_ac_dimmer_gpio_init(void)
 | |
| {
 | |
|     switch (_init_config.zero_cross_port)
 | |
|     {
 | |
|     case AVR_PORTB:
 | |
|         DDRB &= ~(1 << _init_config.zero_cross_gpio);
 | |
|         PORTB |= (1 << _init_config.zero_cross_gpio);
 | |
|         PCICR |= (1 << PCIE0);
 | |
|         PCMSK0 |= (1 << _init_config.zero_cross_gpio);
 | |
|         break;
 | |
|     case AVR_PORTC:
 | |
|         DDRC &= ~(1 << _init_config.zero_cross_gpio);
 | |
|         PORTC |= (1 << _init_config.zero_cross_gpio);
 | |
|         PCICR |= (1 << PCIE1);
 | |
|         PCMSK1 |= (1 << _init_config.zero_cross_gpio);
 | |
|         break;
 | |
|     case AVR_PORTD:
 | |
|         DDRD &= ~(1 << _init_config.zero_cross_gpio);
 | |
|         PORTD |= (1 << _init_config.zero_cross_gpio);
 | |
|         PCICR |= (1 << PCIE2);
 | |
|         PCMSK2 |= (1 << _init_config.zero_cross_gpio);
 | |
|         break;
 | |
|     default:
 | |
|         break;
 | |
|     }
 | |
|     switch (_init_config.triac_port)
 | |
|     {
 | |
|     case AVR_PORTB:
 | |
|         DDRB |= (1 << _init_config.triac_gpio);
 | |
|         PORTB &= ~(1 << _init_config.triac_gpio);
 | |
|         break;
 | |
|     case AVR_PORTC:
 | |
|         DDRC |= (1 << _init_config.triac_gpio);
 | |
|         PORTC &= ~(1 << _init_config.triac_gpio);
 | |
|         break;
 | |
|     case AVR_PORTD:
 | |
|         DDRD |= (1 << _init_config.triac_gpio);
 | |
|         PORTD &= ~(1 << _init_config.triac_gpio);
 | |
|         break;
 | |
|     default:
 | |
|         break;
 | |
|     }
 | |
| }
 | |
| 
 | |
| static avr_err_t _zh_avr_ac_dimmer_timer_init(void)
 | |
| {
 | |
|     TCCR0A |= (1 << WGM01);
 | |
|     switch (F_CPU)
 | |
|     {
 | |
|     case 8000000:
 | |
|         switch (_init_config.ac_dimmer_frequency)
 | |
|         {
 | |
|         case ZH_50HZ:
 | |
|             OCR0A = 94; // Check. 99
 | |
|             TCCR0B |= (1 << CS01);
 | |
|             break;
 | |
|         case ZH_60HZ:
 | |
|             OCR0A = 82;
 | |
|             TCCR0B |= (1 << CS01);
 | |
|             break;
 | |
|         case ZH_400HZ:
 | |
|             OCR0A = 99;
 | |
|             TCCR0B |= (1 << CS00);
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|         break;
 | |
|     case 16000000:
 | |
|         switch (_init_config.ac_dimmer_frequency)
 | |
|         {
 | |
|         case ZH_50HZ:
 | |
|             OCR0A = 24;
 | |
|             TCCR0B |= (1 << CS01) | (1 << CS00);
 | |
|             break;
 | |
|         case ZH_60HZ:
 | |
|             OCR0A = 165;
 | |
|             TCCR0B |= (1 << CS01);
 | |
|             break;
 | |
|         case ZH_400HZ:
 | |
|             OCR0A = 24;
 | |
|             TCCR0B |= (1 << CS01);
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|         break;
 | |
|     case 20000000:
 | |
|         switch (_init_config.ac_dimmer_frequency)
 | |
|         {
 | |
|         case ZH_50HZ:
 | |
|             OCR0A = 249;
 | |
|             TCCR0B |= (1 << CS01);
 | |
|             break;
 | |
|         case ZH_60HZ:
 | |
|             OCR0A = 207;
 | |
|             TCCR0B |= (1 << CS01);
 | |
|             break;
 | |
|         case ZH_400HZ:
 | |
|             OCR0A = 249;
 | |
|             TCCR0B |= (1 << CS00);
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|         break;
 | |
|     default:
 | |
|         return AVR_ERR_INVALID_ARG;
 | |
|         break;
 | |
|     }
 | |
|     return AVR_OK;
 | |
| }
 | |
| 
 | |
| ISR(TIMER0_COMPA_vect)
 | |
| {
 | |
|     ++_dimmer_count;
 | |
|     if (_dimmer_count == (100 - _dimmer_value))
 | |
|     {
 | |
|         _dimmer_count = 0;
 | |
|         TIMSK0 &= ~(1 << OCIE0A);
 | |
|         switch (_init_config.triac_port)
 | |
|         {
 | |
|         case AVR_PORTB:
 | |
|             PORTB |= (1 << _init_config.triac_gpio);
 | |
|             _delay_us(ZH_TRIAC_TIME);
 | |
|             PORTB &= ~(1 << _init_config.triac_gpio);
 | |
|             break;
 | |
|         case AVR_PORTC:
 | |
|             PORTC |= (1 << _init_config.triac_gpio);
 | |
|             _delay_us(ZH_TRIAC_TIME);
 | |
|             PORTC &= ~(1 << _init_config.triac_gpio);
 | |
|         case AVR_PORTD:
 | |
|             PORTD |= (1 << _init_config.triac_gpio);
 | |
|             _delay_us(ZH_TRIAC_TIME);
 | |
|             PORTD &= ~(1 << _init_config.triac_gpio);
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
|     }
 | |
|     TIFR0 = (1 << OCF0A);
 | |
|     // ++_dimmer_count;
 | |
| } |