update
This commit is contained in:
		
							parent
							
								
									bace9ac2d2
								
							
						
					
					
						commit
						afa8ca5d02
					
				@ -1,8 +1,5 @@
 | 
				
			|||||||
# 8. Устройство управления контроллером ШИМ.
 | 
					# 8. Устройство управления контроллером ШИМ.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### TODO:
 | 
					 | 
				
			||||||
- ### Перетащить проект в Microchip Studio, вынести все .h и .c файлы по проекту
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
## Описание
 | 
					## Описание
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Устройство представляет из себя I2C ведущее устройство.
 | 
					### Устройство представляет из себя I2C ведущее устройство.
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										272
									
								
								demo.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										272
									
								
								demo.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,272 @@
 | 
				
			|||||||
 | 
					#define F_CPU 16000000UL
 | 
				
			||||||
 | 
					#define I2C_FREQ 100000UL
 | 
				
			||||||
 | 
					#define I2C_PRESCALER 1
 | 
				
			||||||
 | 
					#define I2C_BITRATE ((F_CPU / I2C_FREQ) - 16) / (2 * I2C_PRESCALER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <avr/io.h>
 | 
				
			||||||
 | 
					#include <avr/interrupt.h>
 | 
				
			||||||
 | 
					#include <util/delay.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float pwm_frequency = 1.0;
 | 
				
			||||||
 | 
					uint8_t pwm_duty_cycle = 50;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile uint8_t pwm_enabled = 0;
 | 
				
			||||||
 | 
					volatile uint8_t pwm_changed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_init() {
 | 
				
			||||||
 | 
					    TWBR = I2C_BITRATE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_start() {
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
 | 
				
			||||||
 | 
					    while (!(TWCR & (1 << TWINT)))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_stop() {
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
 | 
				
			||||||
 | 
					    while (TWCR & (1 << TWSTO))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_write(uint8_t data) {
 | 
				
			||||||
 | 
					    TWDR = data;
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWEN);
 | 
				
			||||||
 | 
					    while (!(TWCR & (1 << TWINT)))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t i2c_read_ack() {
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
 | 
				
			||||||
 | 
					    while (!(TWCR & (1 << TWINT)))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					    return TWDR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t i2c_read_nack() {
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWEN);
 | 
				
			||||||
 | 
					    while (!(TWCR & (1 << TWINT)))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					    return TWDR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const uint8_t PWM_SLAVE_ADDR = 9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_enable() {
 | 
				
			||||||
 | 
					    pwm_enabled = 1;
 | 
				
			||||||
 | 
					    pwm_changed = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_disable() {
 | 
				
			||||||
 | 
					    pwm_enabled = 0;
 | 
				
			||||||
 | 
					    pwm_changed = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setPWMFrequency(float frequency) {
 | 
				
			||||||
 | 
					    if (frequency < 0 || frequency > 50000.0) {
 | 
				
			||||||
 | 
					        return; // Недопустимая частота
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pwm_frequency = frequency;
 | 
				
			||||||
 | 
					    pwm_changed = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setPWMDutyCycle(float duty_cycle) {
 | 
				
			||||||
 | 
					    if (duty_cycle < 1 || duty_cycle > 100) {
 | 
				
			||||||
 | 
					        return; // Недопустимый коэффициент заполнения
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pwm_duty_cycle = duty_cycle;
 | 
				
			||||||
 | 
					    pwm_changed = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_check_state() {
 | 
				
			||||||
 | 
					    if (pwm_enabled) {
 | 
				
			||||||
 | 
					        // Включаем пин ШИМ - реализация зависит от аппаратной платформы
 | 
				
			||||||
 | 
					        Serial.print("PWM enabled. Frequency: ");
 | 
				
			||||||
 | 
					        Serial.print(pwm_frequency);
 | 
				
			||||||
 | 
					        Serial.print(" Hz, duty cycle: ");
 | 
				
			||||||
 | 
					        Serial.println(pwm_duty_cycle);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // Выключаем пин ШИМ - реализация зависит от аппаратной платформы
 | 
				
			||||||
 | 
					        Serial.println("PWM disabled");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_set_frequency(float frequency) {
 | 
				
			||||||
 | 
					    // Устанавливаем частоту ШИМ - реализация зависит от аппаратной платформы
 | 
				
			||||||
 | 
					    Serial.print("Setting PWM frequency to: ");
 | 
				
			||||||
 | 
					    Serial.println(frequency);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_set_duty_cycle(float duty_cycle) {
 | 
				
			||||||
 | 
					    // Устанавливаем коэффициент заполнения ШИМ - реализация зависит от аппаратной платформы
 | 
				
			||||||
 | 
					    Serial.print("Setting PWM duty cycle to: ");
 | 
				
			||||||
 | 
					    Serial.println(duty_cycle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void enablePWM() {
 | 
				
			||||||
 | 
					    pwm_enable();
 | 
				
			||||||
 | 
					    // Включаем ШИМ
 | 
				
			||||||
 | 
					    sendCommand(0x01, 0.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void disablePWM() {
 | 
				
			||||||
 | 
					    // Выключаем ШИМ
 | 
				
			||||||
 | 
					    sendCommand(0x02, 0.0);
 | 
				
			||||||
 | 
					    pwm_disable();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void increaseFrequency() {
 | 
				
			||||||
 | 
					    setPWMFrequency(pwm_frequency * 1.25);
 | 
				
			||||||
 | 
					    // Выключаем ШИМ, отправляем команду и включаем обратно
 | 
				
			||||||
 | 
					    disablePWM();
 | 
				
			||||||
 | 
					    sendCommand(0x03, pwm_frequency);
 | 
				
			||||||
 | 
					    enablePWM();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void decreaseFrequency() {
 | 
				
			||||||
 | 
					    setPWMFrequency(pwm_frequency * 0.8);
 | 
				
			||||||
 | 
					    // Выключаем ШИМ, отправляем команду и включаем обратно
 | 
				
			||||||
 | 
					    disablePWM();
 | 
				
			||||||
 | 
					    sendCommand(0x04, pwm_frequency);
 | 
				
			||||||
 | 
					    enablePWM();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void increaseDutyCycle() {
 | 
				
			||||||
 | 
					    if (pwm_duty_cycle < 100) {
 | 
				
			||||||
 | 
					        pwm_duty_cycle+=10;
 | 
				
			||||||
 | 
					        setPWMDutyCycle(pwm_duty_cycle);
 | 
				
			||||||
 | 
					        // Выключаем ШИМ, отправляем команду и включаем обратно
 | 
				
			||||||
 | 
					        disablePWM();
 | 
				
			||||||
 | 
					        sendCommand(0x05, pwm_duty_cycle);
 | 
				
			||||||
 | 
					        enablePWM();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        Serial.println("Maximum duty cycle reached!");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void decreaseDutyCycle() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (pwm_duty_cycle > 1) {
 | 
				
			||||||
 | 
					        pwm_duty_cycle-=10;
 | 
				
			||||||
 | 
					        setPWMDutyCycle(pwm_duty_cycle);
 | 
				
			||||||
 | 
					        // Выключаем ШИМ, отправляем команду и включаем обратно
 | 
				
			||||||
 | 
					        disablePWM();
 | 
				
			||||||
 | 
					        sendCommand(0x06, pwm_duty_cycle);
 | 
				
			||||||
 | 
					        enablePWM();
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        Serial.println("Minimum duty cycle reached!");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void checkButton(uint8_t pin, const char* message, void (*command)()) {
 | 
				
			||||||
 | 
					    if (bit_is_clear(PINC, pin)) {
 | 
				
			||||||
 | 
					        Serial.println(message);
 | 
				
			||||||
 | 
					        delay(200);
 | 
				
			||||||
 | 
					        command();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // Обновляем состояние ШИМ, если что-то изменилось
 | 
				
			||||||
 | 
					    if (pwm_changed) {
 | 
				
			||||||
 | 
					        pwm_changed = 0;
 | 
				
			||||||
 | 
					        pwm_check_state();
 | 
				
			||||||
 | 
					        if (pwm_enabled) {
 | 
				
			||||||
 | 
					            pwm_set_frequency(pwm_frequency);
 | 
				
			||||||
 | 
					            pwm_set_duty_cycle(pwm_duty_cycle);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setup() {
 | 
				
			||||||
 | 
					    i2c_init();
 | 
				
			||||||
 | 
					    DDRC &= ~(1 << PINC0) & ~(1 << PINC1) & ~(1 << PINC2) & ~(1 << PINC3) & ~(1 << PINC4) & ~(1 << PINC5);
 | 
				
			||||||
 | 
					    PORTC |= (1 << PINC0) | (1 << PINC1) | (1 << PINC2) | (1 << PINC3) | (1 << PINC4) | (1 << PINC5);
 | 
				
			||||||
 | 
					    Serial.begin(9600);
 | 
				
			||||||
 | 
					    Serial.println("PWM Controller started!");
 | 
				
			||||||
 | 
					    sendCommand(0x01, 0.0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void loop() {
 | 
				
			||||||
 | 
					    checkButton(0, "Turn on PWM!", enablePWM);
 | 
				
			||||||
 | 
					    checkButton(1, "Turn off PWM!", disablePWM);
 | 
				
			||||||
 | 
					    checkButton(2, "Increase frequency by 25%!", increaseFrequency);
 | 
				
			||||||
 | 
					    checkButton(3, "Decrease frequency by 20%!", decreaseFrequency);
 | 
				
			||||||
 | 
					    checkButton(4, "Increase duty cycle by 10%!", increaseDutyCycle);
 | 
				
			||||||
 | 
					    checkButton(5, "Decrease duty cycle by 10%!", decreaseDutyCycle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sendCommand(uint8_t cmd, float value) {
 | 
				
			||||||
 | 
					    uint16_t cmd_value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    switch (cmd) {
 | 
				
			||||||
 | 
					        case 0x01:
 | 
				
			||||||
 | 
					        case 0x02:
 | 
				
			||||||
 | 
					            sendCommandOneByte(cmd);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case 0x03:
 | 
				
			||||||
 | 
					        case 0x04:
 | 
				
			||||||
 | 
					            sendCommandThreeBytes(cmd, value);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        case 0x05:
 | 
				
			||||||
 | 
					        case 0x06:
 | 
				
			||||||
 | 
					            sendCommandTwoBytes(cmd, value);
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        default:
 | 
				
			||||||
 | 
					            Serial.println("Unknown command");
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sendCommandOneByte(uint8_t cmd) {
 | 
				
			||||||
 | 
					    i2c_start();
 | 
				
			||||||
 | 
					    i2c_write(PWM_SLAVE_ADDR << 1);
 | 
				
			||||||
 | 
					    i2c_write(cmd);
 | 
				
			||||||
 | 
					    i2c_stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Serial.print("Sent command: 0x");
 | 
				
			||||||
 | 
					    Serial.println(cmd, HEX);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sendCommandTwoBytes(uint8_t cmd, float value) {
 | 
				
			||||||
 | 
					    uint16_t cmd_value = round(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i2c_start();
 | 
				
			||||||
 | 
					    i2c_write(PWM_SLAVE_ADDR << 1);
 | 
				
			||||||
 | 
					    i2c_write(cmd);
 | 
				
			||||||
 | 
					    i2c_write(cmd_value & 0xFF);
 | 
				
			||||||
 | 
					    i2c_stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Serial.print("Sent command: 0x");
 | 
				
			||||||
 | 
					    Serial.print(cmd, HEX);
 | 
				
			||||||
 | 
					    Serial.print(", value: ");
 | 
				
			||||||
 | 
					    Serial.print(value);
 | 
				
			||||||
 | 
					    Serial.print(", cmd value: ");
 | 
				
			||||||
 | 
					    Serial.print(cmd_value);
 | 
				
			||||||
 | 
					    Serial.print(", data bytes: 0x");
 | 
				
			||||||
 | 
					    Serial.println(cmd_value & 0xFF, HEX);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void sendCommandThreeBytes(uint8_t cmd, float value) {
 | 
				
			||||||
 | 
					    uint16_t cmd_value = round(value * 16); // приводим к 12 бит и 4 бита дробной части
 | 
				
			||||||
 | 
					    uint8_t data_bytes[2] = {(cmd_value >> 8) & 0xFF, cmd_value & 0xFF};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    i2c_start();
 | 
				
			||||||
 | 
					    i2c_write(PWM_SLAVE_ADDR << 1);
 | 
				
			||||||
 | 
					    i2c_write(cmd);
 | 
				
			||||||
 | 
					    i2c_write(data_bytes[0]);
 | 
				
			||||||
 | 
					    i2c_write(data_bytes[1]);
 | 
				
			||||||
 | 
					    i2c_stop();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Serial.print("Sent command: 0x");
 | 
				
			||||||
 | 
					    Serial.print(cmd, HEX);
 | 
				
			||||||
 | 
					    Serial.print(", value: ");
 | 
				
			||||||
 | 
					    Serial.print(value);
 | 
				
			||||||
 | 
					    Serial.print(", cmd value: ");
 | 
				
			||||||
 | 
					    Serial.print(cmd_value);
 | 
				
			||||||
 | 
					    Serial.print(", data bytes: 0x");
 | 
				
			||||||
 | 
					    Serial.print(data_bytes[0], HEX);
 | 
				
			||||||
 | 
					    Serial.print(" ");
 | 
				
			||||||
 | 
					    Serial.println(data_bytes[1], HEX);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										38
									
								
								i2c.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								i2c.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					#include "i2c.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_init() {
 | 
				
			||||||
 | 
					    TWBR = I2C_BITRATE;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_start() {
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
 | 
				
			||||||
 | 
					    while (!(TWCR & (1 << TWINT)))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_stop() {
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
 | 
				
			||||||
 | 
					    while (TWCR & (1 << TWSTO))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_write(uint8_t data) {
 | 
				
			||||||
 | 
					    TWDR = data;
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWEN);
 | 
				
			||||||
 | 
					    while (!(TWCR & (1 << TWINT)))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t i2c_read_ack() {
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
 | 
				
			||||||
 | 
					    while (!(TWCR & (1 << TWINT)))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					    return TWDR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					uint8_t i2c_read_nack() {
 | 
				
			||||||
 | 
					    TWCR = (1 << TWINT) | (1 << TWEN);
 | 
				
			||||||
 | 
					    while (!(TWCR & (1 << TWINT)))
 | 
				
			||||||
 | 
					        ;
 | 
				
			||||||
 | 
					    return TWDR;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										18
									
								
								i2c.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								i2c.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					#ifndef I2C_H
 | 
				
			||||||
 | 
					#define I2C_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <avr/io.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define F_CPU 16000000UL
 | 
				
			||||||
 | 
					#define I2C_FREQ 100000UL
 | 
				
			||||||
 | 
					#define I2C_PRESCALER 1
 | 
				
			||||||
 | 
					#define I2C_BITRATE ((F_CPU / I2C_FREQ) - 16) / (2 * I2C_PRESCALER)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void i2c_init();
 | 
				
			||||||
 | 
					void i2c_start();
 | 
				
			||||||
 | 
					void i2c_stop();
 | 
				
			||||||
 | 
					void i2c_write(uint8_t data);
 | 
				
			||||||
 | 
					uint8_t i2c_read_ack();
 | 
				
			||||||
 | 
					uint8_t i2c_read_nack();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										165
									
								
								main.c
									
									
									
									
									
								
							
							
						
						
									
										165
									
								
								main.c
									
									
									
									
									
								
							@ -1,171 +1,10 @@
 | 
				
			|||||||
#define F_CPU 16000000UL
 | 
					 | 
				
			||||||
#define I2C_FREQ 100000UL
 | 
					 | 
				
			||||||
#define I2C_PRESCALER 1
 | 
					 | 
				
			||||||
#define I2C_BITRATE ((F_CPU / I2C_FREQ) - 16) / (2 * I2C_PRESCALER)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <avr/io.h>
 | 
					#include <avr/io.h>
 | 
				
			||||||
#include <avr/interrupt.h>
 | 
					#include <avr/interrupt.h>
 | 
				
			||||||
#include <util/delay.h>
 | 
					#include <util/delay.h>
 | 
				
			||||||
 | 
					#include "pwm.h"
 | 
				
			||||||
float pwm_frequency = 1.0;
 | 
					 | 
				
			||||||
uint8_t pwm_duty_cycle = 50;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
volatile uint8_t pwm_enabled = 0;
 | 
					 | 
				
			||||||
volatile uint8_t pwm_changed = 0;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void i2c_init() {
 | 
					 | 
				
			||||||
    TWBR = I2C_BITRATE;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void i2c_start() {
 | 
					 | 
				
			||||||
    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
 | 
					 | 
				
			||||||
    while (!(TWCR & (1 << TWINT)))
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void i2c_stop() {
 | 
					 | 
				
			||||||
    TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
 | 
					 | 
				
			||||||
    while (TWCR & (1 << TWSTO))
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void i2c_write(uint8_t data) {
 | 
					 | 
				
			||||||
    TWDR = data;
 | 
					 | 
				
			||||||
    TWCR = (1 << TWINT) | (1 << TWEN);
 | 
					 | 
				
			||||||
    while (!(TWCR & (1 << TWINT)))
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint8_t i2c_read_ack() {
 | 
					 | 
				
			||||||
    TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
 | 
					 | 
				
			||||||
    while (!(TWCR & (1 << TWINT)))
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
    return TWDR;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
uint8_t i2c_read_nack() {
 | 
					 | 
				
			||||||
    TWCR = (1 << TWINT) | (1 << TWEN);
 | 
					 | 
				
			||||||
    while (!(TWCR & (1 << TWINT)))
 | 
					 | 
				
			||||||
        ;
 | 
					 | 
				
			||||||
    return TWDR;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
const uint8_t PWM_SLAVE_ADDR = 9;
 | 
					const uint8_t PWM_SLAVE_ADDR = 9;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void pwm_enable() {
 | 
					 | 
				
			||||||
    pwm_enabled = 1;
 | 
					 | 
				
			||||||
    pwm_changed = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pwm_disable() {
 | 
					 | 
				
			||||||
    pwm_enabled = 0;
 | 
					 | 
				
			||||||
    pwm_changed = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void setPWMFrequency(float frequency) {
 | 
					 | 
				
			||||||
    if (frequency < 0 || frequency > 50000.0) {
 | 
					 | 
				
			||||||
        return; // Недопустимая частота
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pwm_frequency = frequency;
 | 
					 | 
				
			||||||
    pwm_changed = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void setPWMDutyCycle(float duty_cycle) {
 | 
					 | 
				
			||||||
    if (duty_cycle < 1 || duty_cycle > 100) {
 | 
					 | 
				
			||||||
        return; // Недопустимый коэффициент заполнения
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    pwm_duty_cycle = duty_cycle;
 | 
					 | 
				
			||||||
    pwm_changed = 1;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pwm_check_state() {
 | 
					 | 
				
			||||||
    if (pwm_enabled) {
 | 
					 | 
				
			||||||
        // Включаем пин ШИМ - реализация зависит от аппаратной платформы
 | 
					 | 
				
			||||||
        Serial.print("PWM enabled. Frequency: ");
 | 
					 | 
				
			||||||
        Serial.print(pwm_frequency);
 | 
					 | 
				
			||||||
        Serial.print(" Hz, duty cycle: ");
 | 
					 | 
				
			||||||
        Serial.println(pwm_duty_cycle);
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        // Выключаем пин ШИМ - реализация зависит от аппаратной платформы
 | 
					 | 
				
			||||||
        Serial.println("PWM disabled");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pwm_set_frequency(float frequency) {
 | 
					 | 
				
			||||||
    // Устанавливаем частоту ШИМ - реализация зависит от аппаратной платформы
 | 
					 | 
				
			||||||
    Serial.print("Setting PWM frequency to: ");
 | 
					 | 
				
			||||||
    Serial.println(frequency);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void pwm_set_duty_cycle(float duty_cycle) {
 | 
					 | 
				
			||||||
    // Устанавливаем коэффициент заполнения ШИМ - реализация зависит от аппаратной платформы
 | 
					 | 
				
			||||||
    Serial.print("Setting PWM duty cycle to: ");
 | 
					 | 
				
			||||||
    Serial.println(duty_cycle);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void enablePWM() {
 | 
					 | 
				
			||||||
    pwm_enable();
 | 
					 | 
				
			||||||
    // Включаем ШИМ
 | 
					 | 
				
			||||||
    sendCommand(0x01, 0.0);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void disablePWM() {
 | 
					 | 
				
			||||||
    // Выключаем ШИМ
 | 
					 | 
				
			||||||
    sendCommand(0x02, 0.0);
 | 
					 | 
				
			||||||
    pwm_disable();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void increaseFrequency() {
 | 
					 | 
				
			||||||
    setPWMFrequency(pwm_frequency * 1.25);
 | 
					 | 
				
			||||||
    // Выключаем ШИМ, отправляем команду и включаем обратно
 | 
					 | 
				
			||||||
    disablePWM();
 | 
					 | 
				
			||||||
    sendCommand(0x03, pwm_frequency);
 | 
					 | 
				
			||||||
    enablePWM();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void decreaseFrequency() {
 | 
					 | 
				
			||||||
    setPWMFrequency(pwm_frequency * 0.8);
 | 
					 | 
				
			||||||
    // Выключаем ШИМ, отправляем команду и включаем обратно
 | 
					 | 
				
			||||||
    disablePWM();
 | 
					 | 
				
			||||||
    sendCommand(0x04, pwm_frequency);
 | 
					 | 
				
			||||||
    enablePWM();
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void increaseDutyCycle() {
 | 
					 | 
				
			||||||
    if (pwm_duty_cycle < 100) {
 | 
					 | 
				
			||||||
        pwm_duty_cycle+=10;
 | 
					 | 
				
			||||||
        setPWMDutyCycle(pwm_duty_cycle);
 | 
					 | 
				
			||||||
        // Выключаем ШИМ, отправляем команду и включаем обратно
 | 
					 | 
				
			||||||
        disablePWM();
 | 
					 | 
				
			||||||
        sendCommand(0x05, pwm_duty_cycle);
 | 
					 | 
				
			||||||
        enablePWM();
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        Serial.println("Maximum duty cycle reached!");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void decreaseDutyCycle() {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (pwm_duty_cycle > 1) {
 | 
					 | 
				
			||||||
        pwm_duty_cycle-=10;
 | 
					 | 
				
			||||||
        setPWMDutyCycle(pwm_duty_cycle);
 | 
					 | 
				
			||||||
        // Выключаем ШИМ, отправляем команду и включаем обратно
 | 
					 | 
				
			||||||
        disablePWM();
 | 
					 | 
				
			||||||
        sendCommand(0x06, pwm_duty_cycle);
 | 
					 | 
				
			||||||
        enablePWM();
 | 
					 | 
				
			||||||
    } else {
 | 
					 | 
				
			||||||
        Serial.println("Minimum duty cycle reached!");
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void checkButton(uint8_t pin, const char* message, void (*command)()) {
 | 
					 | 
				
			||||||
    if (bit_is_clear(PINC, pin)) {
 | 
					 | 
				
			||||||
        Serial.println(message);
 | 
					 | 
				
			||||||
        delay(200);
 | 
					 | 
				
			||||||
        command();
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void setup() {
 | 
					void setup() {
 | 
				
			||||||
    i2c_init();
 | 
					    i2c_init();
 | 
				
			||||||
    DDRC &= ~(1 << PINC0) & ~(1 << PINC1) & ~(1 << PINC2) & ~(1 << PINC3) & ~(1 << PINC4) & ~(1 << PINC5);
 | 
					    DDRC &= ~(1 << PINC0) & ~(1 << PINC1) & ~(1 << PINC2) & ~(1 << PINC3) & ~(1 << PINC4) & ~(1 << PINC5);
 | 
				
			||||||
@ -183,7 +22,6 @@ void loop() {
 | 
				
			|||||||
    checkButton(4, "Increase duty cycle by 10%!", increaseDutyCycle);
 | 
					    checkButton(4, "Increase duty cycle by 10%!", increaseDutyCycle);
 | 
				
			||||||
    checkButton(5, "Decrease duty cycle by 10%!", decreaseDutyCycle);
 | 
					    checkButton(5, "Decrease duty cycle by 10%!", decreaseDutyCycle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Обновляем состояние ШИМ, если что-то изменилось
 | 
					 | 
				
			||||||
    if (pwm_changed) {
 | 
					    if (pwm_changed) {
 | 
				
			||||||
        pwm_changed = 0;
 | 
					        pwm_changed = 0;
 | 
				
			||||||
        pwm_check_state();
 | 
					        pwm_check_state();
 | 
				
			||||||
@ -194,7 +32,6 @@ void loop() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
void sendCommand(uint8_t cmd, float value) {
 | 
					void sendCommand(uint8_t cmd, float value) {
 | 
				
			||||||
    uint16_t cmd_value;
 | 
					    uint16_t cmd_value;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										58
									
								
								pwm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								pwm.c
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					#include "pwm.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					float pwm_frequency = 1.0;
 | 
				
			||||||
 | 
					uint8_t pwm_duty_cycle = 50;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					volatile uint8_t pwm_enabled = 0;
 | 
				
			||||||
 | 
					volatile uint8_t pwm_changed = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_enable() {
 | 
				
			||||||
 | 
					    pwm_enabled = 1;
 | 
				
			||||||
 | 
					    pwm_changed = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_disable() {
 | 
				
			||||||
 | 
					    pwm_enabled = 0;
 | 
				
			||||||
 | 
					    pwm_changed = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setPWMFrequency(float frequency) {
 | 
				
			||||||
 | 
					    if (frequency < 0 || frequency > 50000.0) {
 | 
				
			||||||
 | 
					        return; // Недопустимая частота
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pwm_frequency = frequency;
 | 
				
			||||||
 | 
					    pwm_changed = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void setPWMDutyCycle(float duty_cycle) {
 | 
				
			||||||
 | 
					    if (duty_cycle < 1 || duty_cycle > 100) {
 | 
				
			||||||
 | 
					        return; // Недопустимый коэффициент заполнения
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    pwm_duty_cycle = duty_cycle;
 | 
				
			||||||
 | 
					    pwm_changed = 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_check_state() {
 | 
				
			||||||
 | 
					    if (pwm_enabled) {
 | 
				
			||||||
 | 
					        // Включаем пин ШИМ - реализация зависит от аппаратной платформы
 | 
				
			||||||
 | 
					        Serial.print("PWM enabled. Frequency: ");
 | 
				
			||||||
 | 
					        Serial.print(pwm_frequency);
 | 
				
			||||||
 | 
					        Serial.print(" Hz, duty cycle: ");
 | 
				
			||||||
 | 
					        Serial.println(pwm_duty_cycle);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        // Выключаем пин ШИМ - реализация зависит от аппаратной платформы
 | 
				
			||||||
 | 
					        Serial.println("PWM disabled");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_set_frequency(float frequency) {
 | 
				
			||||||
 | 
					    // Устанавливаем частоту ШИМ - реализация зависит от аппаратной платформы
 | 
				
			||||||
 | 
					    Serial.print("Setting PWM frequency to: ");
 | 
				
			||||||
 | 
					    Serial.println(frequency);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_set_duty_cycle(float duty_cycle) {
 | 
				
			||||||
 | 
					    // Устанавливаем коэффициент заполнения ШИМ - реализация зависит от аппаратной платформы
 | 
				
			||||||
 | 
					    Serial.print("Setting PWM duty cycle to: ");
 | 
				
			||||||
 | 
					    Serial.println(duty_cycle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										33
									
								
								pwm.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								pwm.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
				
			|||||||
 | 
					#ifndef PWM_H
 | 
				
			||||||
 | 
					#define PWM_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <avr/io.h>
 | 
				
			||||||
 | 
					#include "i2c.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern float pwm_frequency;
 | 
				
			||||||
 | 
					extern uint8_t pwm_duty_cycle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern volatile uint8_t pwm_enabled;
 | 
				
			||||||
 | 
					extern volatile uint8_t pwm_changed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void pwm_enable();
 | 
				
			||||||
 | 
					void pwm_disable();
 | 
				
			||||||
 | 
					void setPWMFrequency(float frequency);
 | 
				
			||||||
 | 
					void setPWMDutyCycle(float duty_cycle);
 | 
				
			||||||
 | 
					void pwm_check_state();
 | 
				
			||||||
 | 
					void pwm_set_frequency(float frequency);
 | 
				
			||||||
 | 
					void pwm_set_duty_cycle(float duty_cycle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void enablePWM();
 | 
				
			||||||
 | 
					void disablePWM();
 | 
				
			||||||
 | 
					void increaseFrequency();
 | 
				
			||||||
 | 
					void decreaseFrequency();
 | 
				
			||||||
 | 
					void increaseDutyCycle();
 | 
				
			||||||
 | 
					void decreaseDutyCycle();
 | 
				
			||||||
 | 
					void checkButton(uint8_t pin, const char* message, void (*command)());
 | 
				
			||||||
 | 
					void sendCommand(uint8_t cmd, float value);
 | 
				
			||||||
 | 
					void sendCommandOneByte(uint8_t cmd);
 | 
				
			||||||
 | 
					void sendCommandTwoBytes(uint8_t cmd, float value);
 | 
				
			||||||
 | 
					void sendCommandThreeBytes(uint8_t cmd, float value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user