diff --git a/README.md b/README.md index 5181aa0..ab668b2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,55 @@ -# zh_avr_ac_dimmer +# FreeRTOS based AVR library for AC dimmer +## Features + +1. Support of 50 Hz, 60 Hz and 400 Hz power frequency. + +## Dependencies + +1. [zh_avr_common](http://git.zh.com.ru/avr_libraries/zh_avr_common) + +## Using + +In an existing project, run the following command to install the components: + +```text +cd ../your_project/lib +git clone http://git.zh.com.ru/avr_libraries/zh_avr_common +git clone http://git.zh.com.ru/avr_libraries/zh_avr_ac_dimmer +``` + +In the application, add the component: + +```c +#include "zh_avr_ac_dimmer.h" +``` + +## Examples + +```c +#include "zh_avr_ac_dimmer.h" + +int main(void) +{ + zh_avr_ac_dimmer_init_config_t ac_dimmer_init_config = ZH_AVR_AC_DIMMER_INIT_CONFIG_DEFAULT(); + ac_dimmer_init_config.ac_dimmer_frequency = ZH_50HZ; + ac_dimmer_init_config.zero_cross_port = AVR_PORTD; + ac_dimmer_init_config.zero_cross_gpio = PORTD2; + ac_dimmer_init_config.triac_port = AVR_PORTD; + ac_dimmer_init_config.triac_gpio = PORTD3; + zh_avr_ac_dimmer_init(&ac_dimmer_init_config); + zh_avr_ac_dimmer_set(50); + zh_avr_ac_dimmer_start(); + for (;;) + { + } + return 0; +} + +// ISR(PCINT0_vect) // For AVR_PORTB. +// ISR(PCINT1_vect) // For AVR_PORTC. +ISR(PCINT2_vect) // For AVR_PORTD. +{ + zh_avr_ac_dimmer_isr_handler(); +} +``` diff --git a/include/zh_avr_ac_dimmer.h b/include/zh_avr_ac_dimmer.h index fd71481..ecba712 100644 --- a/include/zh_avr_ac_dimmer.h +++ b/include/zh_avr_ac_dimmer.h @@ -23,8 +23,8 @@ extern "C" typedef enum { ZH_50HZ = 1, - ZH_60HZ, - ZH_400HZ + ZH_60HZ = 2, + ZH_400HZ = 3 } zh_avr_ac_dimmer_frequency_t; typedef struct // Structure for initial initialization of AC dimmer. @@ -72,6 +72,11 @@ extern "C" */ avr_err_t zh_avr_ac_dimmer_set(uint8_t value); + /** + * @brief AC dimmer ISR handler. + */ + void zh_avr_ac_dimmer_isr_handler(void); + #ifdef __cplusplus } #endif \ No newline at end of file diff --git a/triac_400hz_delay — копия.xlsx b/triac_400hz_delay — копия.xlsx deleted file mode 100644 index aa41f37..0000000 Binary files a/triac_400hz_delay — копия.xlsx and /dev/null differ diff --git a/triac_400hz_delay.xlsx b/triac_400hz_delay.xlsx deleted file mode 100644 index aa41f37..0000000 Binary files a/triac_400hz_delay.xlsx and /dev/null differ diff --git a/zh_avr_ac_dimmer.c b/zh_avr_ac_dimmer.c index cbfb82e..e37abfc 100644 --- a/zh_avr_ac_dimmer.c +++ b/zh_avr_ac_dimmer.c @@ -1,81 +1,115 @@ #include "zh_avr_ac_dimmer.h" +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; +static uint8_t _prescaler = 0; 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); -static avr_err_t zh_avr_ac_dimmer_init(const zh_avr_ac_dimmer_init_config_t *config) +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_pcf8574_validate_config(config); + avr_err_t err = _zh_avr_ac_dimmer_validate_config(config); ZH_ERROR_CHECK(err == AVR_OK, err); - switch (config->zero_cross_port) - { - case AVR_PORTB: - DDRB &= ~(1 << config->zero_cross_gpio); - PORTB |= (1 << config->zero_cross_gpio); - PCICR |= (1 << PCIE0); - PCMSK0 |= (1 << config->zero_cross_gpio); - break; - case AVR_PORTC: - DDRC &= ~(1 << config->zero_cross_gpio); - PORTC |= (1 << config->zero_cross_gpio); - PCICR |= (1 << PCIE1); - PCMSK1 |= (1 << config->zero_cross_gpio); - break; - case AVR_PORTD: - DDRD &= ~(1 << config->zero_cross_gpio); - PORTD |= (1 << config->zero_cross_gpio); - PCICR |= (1 << PCIE2); - PCMSK2 |= (1 << config->zero_cross_gpio); - break; - default: - break; - } - switch (config->triac_port) - { - case AVR_PORTB: - DDRB |= (1 << config->triac_gpio); - PORTB &= ~(1 << config->triac_gpio); - break; - case AVR_PORTC: - DDRC |= (1 << config->triac_gpio); - PORTC &= ~(1 << config->triac_gpio); - break; - case AVR_PORTD: - DDRD |= (1 << config->triac_gpio); - PORTD &= ~(1 << config->triac_gpio); - break; - default: - break; - } + _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; } -static avr_err_t zh_avr_ac_dimmer_start(void) +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; } -static avr_err_t zh_avr_ac_dimmer_stop(void) +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; } -static avr_err_t zh_avr_ac_dimmer_set(uint8_t value) +avr_err_t zh_avr_ac_dimmer_set(uint8_t value) { ZH_ERROR_CHECK(_dimmer_value <= 100, AVR_ERR_INVALID_ARG); _dimmer_value = value; return AVR_OK; } +void zh_avr_ac_dimmer_isr_handler(void) +{ + uint8_t flag = false; + switch (_init_config.zero_cross_port) + { + case AVR_PORTB: + if ((PINB & (1 << _init_config.zero_cross_gpio)) == 0) + { + flag = true; + } + break; + case AVR_PORTC: + if ((PINC & (1 << _init_config.zero_cross_gpio)) == 0) + { + flag = true; + } + break; + case AVR_PORTD: + if ((PIND & (1 << _init_config.zero_cross_gpio)) == 0) + { + flag = true; + } + break; + default: + break; + } + if (_is_dimmer_work == true && flag == true) + { + if (_dimmer_value != 0) + { + if (_dimmer_value == 100) + { + switch (_init_config.triac_port) + { + case AVR_PORTB: + PORTB |= (1 << _init_config.triac_gpio); + asm("nop"); + PORTB &= ~(1 << _init_config.triac_gpio); + break; + case AVR_PORTC: + PORTC |= (1 << _init_config.triac_gpio); + asm("nop"); + PORTC &= ~(1 << _init_config.triac_gpio); + break; + case AVR_PORTD: + PORTD |= (1 << _init_config.triac_gpio); + asm("nop"); + PORTD &= ~(1 << _init_config.triac_gpio); + break; + default: + break; + } + } + else + { + TCNT0 = 0; + TCCR0B |= _prescaler; + TIMSK0 |= (1 << OCIE0A); + } + } + } +} + 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); @@ -85,4 +119,148 @@ static avr_err_t _zh_avr_ac_dimmer_validate_config(const zh_avr_ac_dimmer_init_c 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 = 99; + _prescaler = (1 << CS01); + break; + case ZH_60HZ: + OCR0A = 82; + _prescaler = (1 << CS01); + break; + case ZH_400HZ: + OCR0A = 99; + _prescaler = (1 << CS00); + break; + default: + break; + } + break; + case 16000000: + switch (_init_config.ac_dimmer_frequency) + { + case ZH_50HZ: + OCR0A = 24; + _prescaler = (1 << CS01) | (1 << CS00); + break; + case ZH_60HZ: + OCR0A = 165; + _prescaler = (1 << CS01); + break; + case ZH_400HZ: + OCR0A = 24; + _prescaler = (1 << CS01); + break; + default: + break; + } + break; + case 20000000: + switch (_init_config.ac_dimmer_frequency) + { + case ZH_50HZ: + OCR0A = 249; + _prescaler = (1 << CS01); + break; + case ZH_60HZ: + OCR0A = 206; + _prescaler = (1 << CS01); + break; + case ZH_400HZ: + OCR0A = 249; + _prescaler = (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; + TCCR0B &= ~_prescaler; + TIMSK0 &= ~(1 << OCIE0A); + switch (_init_config.triac_port) + { + case AVR_PORTB: + PORTB |= (1 << _init_config.triac_gpio); + asm("nop"); + PORTB &= ~(1 << _init_config.triac_gpio); + break; + case AVR_PORTC: + PORTC |= (1 << _init_config.triac_gpio); + asm("nop"); + PORTC &= ~(1 << _init_config.triac_gpio); + break; + case AVR_PORTD: + PORTD |= (1 << _init_config.triac_gpio); + asm("nop"); + PORTD &= ~(1 << _init_config.triac_gpio); + break; + default: + break; + } + } } \ No newline at end of file