From afa8ca5d0249a82b121b383389ba4cefe889ef13 Mon Sep 17 00:00:00 2001 From: zloihach <72695485+zloihach@users.noreply.github.com> Date: Mon, 26 Jun 2023 23:58:53 +0300 Subject: [PATCH] update --- README.md | 3 - demo.c | 272 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ i2c.c | 38 ++++++++ i2c.h | 18 ++++ main.c | 165 +-------------------------------- pwm.c | 58 ++++++++++++ pwm.h | 33 +++++++ 7 files changed, 420 insertions(+), 167 deletions(-) create mode 100644 demo.c create mode 100644 i2c.c create mode 100644 i2c.h create mode 100644 pwm.c create mode 100644 pwm.h diff --git a/README.md b/README.md index e8908ad..7fc3fe7 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,5 @@ # 8. Устройство управления контроллером ШИМ. -### TODO: -- ### Перетащить проект в Microchip Studio, вынести все .h и .c файлы по проекту - ## Описание ### Устройство представляет из себя I2C ведущее устройство. diff --git a/demo.c b/demo.c new file mode 100644 index 0000000..aae557e --- /dev/null +++ b/demo.c @@ -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 +#include +#include + +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); +} \ No newline at end of file diff --git a/i2c.c b/i2c.c new file mode 100644 index 0000000..8154c08 --- /dev/null +++ b/i2c.c @@ -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; +} \ No newline at end of file diff --git a/i2c.h b/i2c.h new file mode 100644 index 0000000..338d7f2 --- /dev/null +++ b/i2c.h @@ -0,0 +1,18 @@ +#ifndef I2C_H +#define I2C_H + +#include + +#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 \ No newline at end of file diff --git a/main.c b/main.c index ead4413..44adfd6 100644 --- a/main.c +++ b/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 #include #include - -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; -} +#include "pwm.h" 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() { i2c_init(); 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(5, "Decrease duty cycle by 10%!", decreaseDutyCycle); - // Обновляем состояние ШИМ, если что-то изменилось if (pwm_changed) { pwm_changed = 0; pwm_check_state(); @@ -194,7 +32,6 @@ void loop() { } } - void sendCommand(uint8_t cmd, float value) { uint16_t cmd_value; diff --git a/pwm.c b/pwm.c new file mode 100644 index 0000000..da9ba67 --- /dev/null +++ b/pwm.c @@ -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); +} \ No newline at end of file diff --git a/pwm.h b/pwm.h new file mode 100644 index 0000000..26caa6b --- /dev/null +++ b/pwm.h @@ -0,0 +1,33 @@ +#ifndef PWM_H +#define PWM_H + +#include +#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 \ No newline at end of file