diff --git a/main.c b/main.c index e3c8b14..ead4413 100644 --- a/main.c +++ b/main.c @@ -8,7 +8,7 @@ #include float pwm_frequency = 1.0; -float pwm_duty_cycle = 0.5; +uint8_t pwm_duty_cycle = 50; volatile uint8_t pwm_enabled = 0; volatile uint8_t pwm_changed = 0; @@ -63,7 +63,7 @@ void pwm_disable() { } void setPWMFrequency(float frequency) { - if (frequency < 1.0 || frequency > 50000.0) { + if (frequency < 0 || frequency > 50000.0) { return; // Недопустимая частота } pwm_frequency = frequency; @@ -71,7 +71,7 @@ void setPWMFrequency(float frequency) { } void setPWMDutyCycle(float duty_cycle) { - if (duty_cycle < 0.0 || duty_cycle > 1.0) { + if (duty_cycle < 1 || duty_cycle > 100) { return; // Недопустимый коэффициент заполнения } pwm_duty_cycle = duty_cycle; @@ -132,8 +132,9 @@ void decreaseFrequency() { } void increaseDutyCycle() { - if (pwm_duty_cycle < 0.9) { - setPWMDutyCycle(pwm_duty_cycle * 1.1); + if (pwm_duty_cycle < 100) { + pwm_duty_cycle+=10; + setPWMDutyCycle(pwm_duty_cycle); // Выключаем ШИМ, отправляем команду и включаем обратно disablePWM(); sendCommand(0x05, pwm_duty_cycle); @@ -144,8 +145,10 @@ void increaseDutyCycle() { } void decreaseDutyCycle() { - if (pwm_duty_cycle > 0.1) { - setPWMDutyCycle(pwm_duty_cycle*0.9); + + if (pwm_duty_cycle > 1) { + pwm_duty_cycle-=10; + setPWMDutyCycle(pwm_duty_cycle); // Выключаем ШИМ, отправляем команду и включаем обратно disablePWM(); sendCommand(0x06, pwm_duty_cycle); @@ -193,27 +196,47 @@ void loop() { void sendCommand(uint8_t cmd, float value) { - // Приводим значение к 12 битам для целой части и 4 битам для дробной части - uint16_t integer_part = (uint16_t)value; - uint8_t fractional_part = (uint8_t)((value - integer_part) * 16); + uint16_t cmd_value; - // Проверяем, чтобы значение не превышало допустимых границ - if (integer_part > 0xFFF) { - integer_part = 0xFFF; - } - if (fractional_part > 0xF) { - fractional_part = 0xF; - } + switch (cmd) { + case 0x01: + case 0x02: + sendCommandOneByte(cmd); + break; - // Формируем 4 байта данных для отправки - uint8_t upper_byte = (integer_part >> 4) & 0xFF; - uint8_t lower_byte = ((integer_part & 0xF) << 4) | (fractional_part & 0xF); + 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(upper_byte); - i2c_write(lower_byte); + i2c_write(cmd_value & 0xFF); i2c_stop(); Serial.print("Sent command: 0x"); @@ -221,36 +244,30 @@ void sendCommand(uint8_t cmd, float value) { Serial.print(", value: "); Serial.print(value); Serial.print(", cmd value: "); - Serial.print((integer_part << 4) | fractional_part); + Serial.print(cmd_value); Serial.print(", data bytes: 0x"); - Serial.print(upper_byte, HEX); - Serial.print(" "); - Serial.println(lower_byte, HEX); + 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(); - -// void sendCommand(uint8_t cmd, float value) { -// uint16_t cmd_value = ((uint16_t)cmd << 8) | (uint16_t)(value * 16); -// uint8_t upper_byte = cmd_value >> 8; -// uint8_t lower_byte = cmd_value & 0xFF; - -// i2c_start(); -// i2c_write(PWM_SLAVE_ADDR << 1); -// i2c_write(cmd); -// i2c_write(upper_byte); -// i2c_write(lower_byte); -// i2c_stop(); - -// Serial.print("Sent command: 0x"); -// Serial.print(cmd, HEX); -// Serial.print(", value: "); -// Serial.print(cmd_value / 16); -// Serial.print(", cmd value: "); -// Serial.print(cmd_value); -// Serial.print(", data bytes: 0x"); -// Serial.print(upper_byte, HEX); -// Serial.print(" "); -// Serial.println(lower_byte, HEX); -// } \ No newline at end of file + 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/slave/slave.c b/slave/slave.c new file mode 100644 index 0000000..3d7faa8 --- /dev/null +++ b/slave/slave.c @@ -0,0 +1,290 @@ +// #include +// #include + +// #define SLAVE_ADDRESS 9 // адрес устройства slave +// #define COMMAND_1 0x01 //команда включения шим +// #define COMMAND_2 0x02 //команда выключения шим +// #define COMMAND_3 0x03 //команда изменения частоты шим +// #define COMMAND_4 0x04 //команда изменения скважности шим +// #define COMMAND_5 0x05 //команда изменения скважности шим + + +// uint16_t frequency = 1 << 4; +// uint8_t dutycycle = 50; +// uint8_t buffer[32]; // буфер для полученных данных +// uint8_t cnt = 0; // счетчик байтов +// bool tran_end = false; //флаг окончания передачи + +// void i2c_init() { +// TWAR = SLAVE_ADDRESS << 1; // задаем адрес устройства +// TWSR = 0; // частота шины 100 кГц (скорость передачи) +// TWCR = (1 << TWEN) | (1 << TWEA) | (1 << TWIE); // включаем slave reciever +// } + +// // обработчик прерывания TWI +// ISR(TWI_vect) { +// switch (TWSR) { +// case 0x60: // SLA+W received, ACK returned +// //cnt = 0; // сброс счетчика +// //tran_end = false; +// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); // включаем прерывание и устанавливаем бит ACK +// break; +// case 0x80: // data byte received, ACK returned +// buffer[cnt++] = TWDR; // сохраняем принятые данные +// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); +// break; +// case 0x88: // last data byte received, NACK returned +// buffer[cnt++] = TWDR; // сохраняем последний байт данных +// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); +// break; +// case 0xA0: // STOP or repeated START received +// tran_end = true; +// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); +// break; +// default: +// TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); +// break; +// } +// } + +// void timer1_init() { +// PORTB = 0; +// DDRB |= (1 << PORTB1); //OC1A +// DDRB |= (1 << PORTB2); //OC1B +// TCCR1A = 0; // обнуляем регистры управления +// TCCR1B = 0; +// TCNT1 = 0; // и счетный регистр +// } + +// //частота приходит в 16 раз больше +// void timer1_on(uint16_t frequency, uint8_t dutycycle) { +// // Неинверсный режим работы +// TCCR1A |= (0 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0); + +// //Fast PWM (Быстрый ШИМ) +// TCCR1A |= (1 << WGM11) | (1 << WGM10); +// TCCR1B |= (1 << WGM13) | (1 << WGM12); + +// //Предделитель - 1024 +// TCCR1B |= (1 << CS12) | (0 << CS11) | (1 << CS10); + +// //Частота +// OCR1A = F_CPU / 1024 * 16 / frequency; + +// //Скважность +// OCR1B = (F_CPU / 1024 * 16 / frequency) * dutycycle / 100; +// } + +// void timer1_off() { +// // TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0)); +// //Fast PWM (Быстрый ШИМ) +// TCCR1A |= (0 << WGM11) | (0 << WGM10); +// TCCR1B |= (0 << WGM13) | (0 << WGM12); +// TCCR1A |= (0 << COM1A1) | (0 << COM1A0) | (0 << COM1B1) | (0 << COM1B0); //шим отключен, нормальная работа порта +// TCCR1B = 0; + +// // OCR1A = 0; +// // OCR1B = 0; +// } + +// void setup(void) { +// i2c_init(); //инициализация i2c +// timer1_init(); +// Serial.begin(9600); +// Serial.println("PWM Slave started!"); +// sei(); // включаем прерывания +// } + + +// void loop() { +// if (tran_end) { +// tran_end = false; +// for(int i = 0;i<100;i++){ +// } +// if (buffer[0] == COMMAND_1) { +// Serial.print("cmd: 0x"); +// Serial.println(buffer[0]); +// timer1_on(frequency, dutycycle); +// Serial.print(", data bytes: "); +// Serial.print(buffer[1], HEX); +// Serial.print(" "); +// Serial.println(buffer[2], HEX); // Включение ШИМ +// } else if (buffer[0] == COMMAND_2) { +// Serial.print("cmd: 0x"); +// Serial.println(buffer[0]); +// timer1_off(); +// Serial.print(", data bytes: "); +// Serial.print(buffer[1], HEX); +// Serial.print(" "); +// Serial.println(buffer[2], HEX); // Выключение ШИМ +// } else if (buffer[0] == COMMAND_3) { +// Serial.print("cmd: 0x"); +// Serial.println(buffer[0]); +// frequency = (buffer[1] << 8) + buffer[2]; +// Serial.print("frequency value: "); +// Serial.print(frequency); +// Serial.print(", data bytes: "); +// Serial.print(buffer[1], HEX); +// Serial.print(" "); +// Serial.println(buffer[2], HEX); +// } else if (buffer[0] == COMMAND_4) { +// Serial.print("cmd: 0x"); +// Serial.println(buffer[0]); +// frequency = (buffer[1] << 8) + buffer[2]; +// Serial.print("frequency value: "); +// Serial.print(frequency); +// Serial.print(", data bytes: "); +// Serial.print(buffer[1], HEX); +// Serial.print(" "); +// Serial.println(buffer[2], HEX); +// } else if (buffer[0] == COMMAND_5) { +// Serial.print("cmd: 0x"); +// Serial.println(buffer[0]); +// dutycycle = buffer[1]; +// Serial.print("dytycycle value: "); +// Serial.println(dutycycle); +// Serial.print(", data bytes: "); +// Serial.print(buffer[1], HEX); +// Serial.print(" "); +// Serial.println(buffer[2], HEX); +// } else if (buffer[0] == COMMAND_5) { +// Serial.print("cmd: 0x"); +// Serial.println(buffer[0]); +// dutycycle = buffer[1]; +// Serial.print("dytycycle value: "); +// Serial.println(dutycycle); +// Serial.print(", data bytes: "); +// Serial.print(buffer[1], HEX); +// Serial.print(" "); +// Serial.println(buffer[2], HEX); +// } +// cnt = 0; +// } +// } + + +#include +#include + +#define SLAVE_ADDRESS 9 // адрес устройства slave +#define COMMAND_1 0x01 //команда включения шим +#define COMMAND_2 0x02 //команда выключения шим +#define COMMAND_3 0x03 //команда изменения частоты шим +#define COMMAND_4 0x04 //команда изменения скважности шим +#define COMMAND_5 0x05 //команда изменения скважности шим +#define COMMAND_6 0x06 //команда изменения скважности шим + + + +uint16_t frequency = 1 << 4; +uint8_t dutycycle = 50; +uint8_t buffer[32]; // буфер для полученных данных +uint8_t cnt = 0; // счетчик байтов +bool tran_end = false; //флаг окончания передачи + +void i2c_init() { + TWAR = SLAVE_ADDRESS << 1; // задаем адрес устройства + TWSR = 0; // частота шины 100 кГц (скорость передачи) + TWCR = (1 << TWEN) | (1 << TWEA) | (1 << TWIE); // включаем slave reciever +} + +// обработчик прерывания TWI +ISR(TWI_vect) { + switch (TWSR) { + case 0x60: // SLA+W received, ACK returned + //cnt = 0; // сброс счетчика + //tran_end = false; + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); // включаем прерывание и устанавливаем бит ACK + break; + case 0x80: // data byte received, ACK returned + buffer[cnt++] = TWDR; // сохраняем принятые данные + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); + break; + case 0x88: // last data byte received, NACK returned + buffer[cnt++] = TWDR; // сохраняем последний байт данных + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); + break; + case 0xA0: // STOP or repeated START received + tran_end = true; + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); + break; + default: + TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); + break; + } +} + +void timer1_init() { + PORTB = 0; + DDRB |= (1 << PORTB1); //OC1A + DDRB |= (1 << PORTB2); //OC1B + TCCR1A = 0; // обнуляем регистры управления + TCCR1B = 0; + TCNT1 = 0; // и счетный регистр +} + +//частота приходит в 16 раз больше +void timer1_on(uint16_t frequency, uint8_t dutycycle) { + // Неинверсный режим работы + TCCR1A |= (0 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0); + + //Fast PWM (Быстрый ШИМ) + TCCR1A |= (1 << WGM11) | (1 << WGM10); + TCCR1B |= (1 << WGM13) | (1 << WGM12); + + //Предделитель - 1024 + TCCR1B |= (1 << CS12) | (0 << CS11) | (1 << CS10); + + //Частота + OCR1A = F_CPU / 1024 * 16 / frequency; + + //Скважность + OCR1B = (F_CPU / 1024 * 16 / frequency) * dutycycle / 100; +} + +void timer1_off() { + // TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0)); + //Fast PWM (Быстрый ШИМ) + TCCR1A |= (0 << WGM11) | (0 << WGM10); + TCCR1B |= (0 << WGM13) | (0 << WGM12); + TCCR1A |= (0 << COM1A1) | (0 << COM1A0) | (0 << COM1B1) | (0 << COM1B0); //шим отключен, нормальная работа порта + TCCR1B = 0; + + // OCR1A = 0; + // OCR1B = 0; +} + +void setup(void) { + i2c_init(); //инициализация i2c + timer1_init(); + Serial.begin(9600); + Serial.println("PWM Slave started!"); + sei(); // включаем прерывания +} + + +void loop() { + if (tran_end) { + tran_end = false; + Serial.println(" "); + + for (int i = 0; i < cnt; i++) { + Serial.print(buffer[i], HEX); // вывод байтов в шестнадцатеричном формате + Serial.print(" "); + } + if (buffer[0] == COMMAND_1) { + timer1_on(frequency, dutycycle); + } else if (buffer[0] == COMMAND_2) { + timer1_off(); + } else if (buffer[0] == COMMAND_3) { + frequency = (buffer[1] << 8) + buffer[2]; + } else if (buffer[0] == COMMAND_4) { + frequency = (buffer[1] << 8) + buffer[2]; + } else if (buffer[0] == COMMAND_5) { + dutycycle = buffer[1]; + } else if (buffer[0] == COMMAND_6) { + dutycycle = buffer[1]; + } + cnt = 0; + } +} \ No newline at end of file diff --git a/slave/slave.cpp b/slave/slave.cpp deleted file mode 100644 index 6c89923..0000000 --- a/slave/slave.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -void setup() { - Wire.begin(9); // Устанавливаем адрес слейва - Wire.onReceive(receiveEvent); // Указываем функцию для обработки приема данных - Serial.begin(9600); -} - -void loop() { - // Здесь можно добавить другие действия слейва, если необходимо -} - -void receiveEvent(int numBytes) { - while (Wire.available()) { - uint8_t cmd = Wire.read(); - uint8_t upper_byte = Wire.read(); - uint8_t lower_byte = Wire.read(); - - uint16_t cmd_value = (upper_byte << 8) | lower_byte; - float value = cmd_value / 16.0; - - Serial.print("Received command: 0x"); - Serial.print(cmd, HEX); - Serial.print(", value: "); - Serial.println(value); - } -} \ No newline at end of file diff --git a/slave/slave_v2.c b/slave/slave_v2.c deleted file mode 100644 index 13b4361..0000000 --- a/slave/slave_v2.c +++ /dev/null @@ -1,144 +0,0 @@ -// -// Created by FSB-PC on 23.06.2023. -// - -// #include - -// void setup() { -// Wire.begin(9); // Устанавливаем адрес слейва -// Wire.onReceive(receiveEvent); // Указываем функцию для обработки приема данных -// Serial.begin(9600); -// } - -// void loop() { -// // Здесь можно добавить другие действия слейва, если необходимо -// } - -// void receiveEvent(int numBytes) { -// while (Wire.available()) { -// uint8_t cmd = Wire.read(); -// uint8_t upper_byte = Wire.read(); -// uint8_t lower_byte = Wire.read(); - -// uint16_t cmd_value = (upper_byte << 8) | lower_byte; -// float value = cmd_value / 16.0; - -// Serial.print("Received command: 0x"); -// Serial.print(cmd, HEX); -// Serial.print(", value: "); -// Serial.print(value); - -// Serial.print(", data bytes: 0x"); -// Serial.print(upper_byte, HEX); -// Serial.print(" "); -// Serial.println(lower_byte, HEX); -// } -// } - - -#include -#include - -#define SLAVE_ADDRESS 9 // адрес устройства slave -#define COMMAND_1 0x01 //команда включения шим -#define COMMAND_2 0x02 //команда выключения шим -#define COMMAND_3 0x03 //команда изменения частоты шим -#define COMMAND_4 0x04 //команда изменения скважности шим - -uint16_t frequency = 1 << 4; -uint8_t dutycycle = 50; -uint8_t buffer[32]; // буфер для полученных данных -uint8_t cnt = 0; // счетчик байтов -bool tran_end = false; //флаг окончания передачи - -void i2c_init() { - TWAR = SLAVE_ADDRESS << 1; // задаем адрес устройства - TWSR = 0; // частота шины 100 кГц (скорость передачи) - TWCR = (1 << TWEN) | (1 << TWEA) | (1 << TWIE); // включаем slave reciever -} - -// обработчик прерывания TWI -ISR(TWI_vect) { - switch (TWSR) { - case 0x60: // SLA+W received, ACK returned - //cnt = 0; // сброс счетчика - //tran_end = false; - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); // включаем прерывание и устанавливаем бит ACK - break; - case 0x80: // data byte received, ACK returned - buffer[cnt++] = TWDR; // сохраняем принятые данные - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); - break; - case 0x88: // last data byte received, NACK returned - buffer[cnt++] = TWDR; // сохраняем последний байт данных - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); - break; - case 0xA0: // STOP or repeated START received - tran_end = true; - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); - break; - default: - TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA) | (1 << TWIE); - break; - } -} - -void timer1_init() { - PORTB = 0; - DDRB |= (1 << PORTB1); //OC1A - DDRB |= (1 << PORTB2); //OC1B - TCCR1A = 0; // обнуляем регистры управления - TCCR1B = 0; - TCNT1 = 0; // и счетный регистр -} - -//частота приходит в 16 раз больше -void timer1_on(uint16_t frequency, uint8_t dutycycle) { - // Неинверсный режим работы - TCCR1A |= (0 << COM1A1) | (0 << COM1A0) | (1 << COM1B1) | (0 << COM1B0); - - //Fast PWM (Быстрый ШИМ) - TCCR1A |= (1 << WGM11) | (1 << WGM10); - TCCR1B |= (1 << WGM13) | (1 << WGM12); - - //Предделитель - 1024 - TCCR1B |= (1 << CS12) | (0 << CS11) | (1 << CS10); - - //Частота - OCR1A = F_CPU / 1024 * 16 / frequency; - - //Скважность - OCR1B = (F_CPU / 1024 * 16 / frequency) * dutycycle / 100; -} - -void timer1_off() { - TCCR1A |= (0 << COM1A1) | (0 << COM1A0) | (0 << COM1B1) | (0 << COM1B0); //шим отключен, нормальная работа порта -} - -void setup(void) { - i2c_init(); //инициализация i2c - timer1_init(); - Serial.begin(9600); - Serial.println("PWM Slave started!"); - sei(); // включаем прерывания -} - -void loop() { - if (tran_end) { - tran_end = false; - if (buffer[0] == COMMAND_1) { - Serial.println(buffer[0]); - timer1_on(frequency, dutycycle); // Включение ШИМ - } else if (buffer[0] == COMMAND_2) { - Serial.println(buffer[0]); - timer1_off(); // Выключение ШИМ - } else if (buffer[0] == COMMAND_3) { - Serial.println(buffer[0]); - - frequency = (buffer[1] << 8) + buffer[2]; - } else if (buffer[0] == COMMAND_4) { - dutycycle = buffer[1]; - } - cnt = 0; - } -}