8.Master_I2C_PWM/main.cpp
2023-06-22 18:31:13 +03:00

166 lines
5.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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() {
TWBR = I2C_BITRATE;
}
void i2c_start() {
// отправляем START bit
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
// ожидаем пока START bit будет успешно отправлен
while (!(TWCR & (1 << TWINT)));
}
void i2c_stop() {
// отправляем STOP bit
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
// ожидаем пока STOP bit будет успешно отправлен
while (TWCR & (1 << TWSTO));
}
void i2c_write(uint8_t data) {
// загружаем данные в регистр TWDR
TWDR = data;
// отправляем данные
TWCR = (1 << TWINT) | (1 << TWEN);
// ожидаем пока данные будут успешно отправлены
while (!(TWCR & (1 << TWINT)));
}
uint8_t i2c_read_ack() {
// разрешаем отправку ACK после прочтения байта
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
// ожидаем пока данные будут успешно прочитаны
while (!(TWCR & (1 << TWINT)));
// возвращаем прочитанный байт
return TWDR;
}
uint8_t i2c_read_nack() {
// запрещаем отправку ACK после прочтения байта
TWCR = (1 << TWINT) | (1 << TWEN);
// ожидаем пока данные будут успешно прочитаны
while (!(TWCR & (1 << TWINT)));
// возвращаем прочитанный байт
return TWDR;
}
const uint8_t BUTTON_PIN[] = {0, 1, 2, 3, 4, 5};
const uint8_t PWM_SLAVE_ADDR = 9;
uint16_t command = 0x00;
float frequency = pwm_get_frequency();
float dutyCycle = pwm_get_duty_cycle();
void setup() {
i2c_init();
pwm_init();
pwm_enable(); // Включение ШИМ
// Инициализируем пины кнопок
DDRC &= ~(1 << PINC0) & ~(1 << PINC1) & ~(1 << PINC2) & ~(1 << PINC3) & ~(1 << PINC4) & ~(1 << PINC5); // подключены кнопки на пинах А0, А1, А2, А3, А4, А5
PORTC |= (1 << PINC0) | (1 << PINC1) | (1 << PINC2) | (1 << PINC3) | (1 << PINC4) | (1 << PINC5); // включение подтягивающего резистора
Serial.begin(9600); // Инициализируем Serial монитор
Serial.println("PWM Controller started!");
Serial.println("PWM on master device initial successful!");
sendCommand(0x01, 0.0); // Включить ШИМ при запуске
}
void loop() {
// Обработка нажатий на кнопки
checkButton(0, "Turn on PWM!", 0x01, 0.0);
checkButton(1, "Turn off PWM!", 0x02, 0.0);
checkButton(2, "Increase frequency!", 0x03, 1.25);
checkButton(3, "Decrease frequency!", 0x04, 0.8);
checkButton(4, "Increase duty cycle!", 0x05, 1.1);
checkButton(5, "Decrease duty cycle!", 0x06, 0.9);
}
void checkButton(uint8_t pin, const char* message, uint16_t cmd, float value) {
if (bit_is_clear(PINC, pin)) {
Serial.println(message);
delay(1000);
switch(cmd) {
case 0x03:
case 0x04:
frequency *= value;
pwm_set_frequency(frequency);
sendCommand(cmd, value);
break;
case 0x05:
case 0x06:
dutyCycle *= value;
pwm_set_duty_cycle(dutyCycle);
sendCommand(cmd, value);
break;
case 0x02:
pwm_disable();
sendCommand(cmd, value);
pwm_check_state();
break;
case 0x01:
pwm_enable();
sendCommand(cmd, value);
pwm_check_state();
break;
}
command = cmd;
}
}
void sendCommand(uint16_t cmd, float value) {
// Проверяем, является ли команда изменением частоты или коэффициента заполнения
if (cmd == 0x03 || cmd == 0x04) {
value = pwm_get_frequency(); // Если да, получаем текущее значение частоты
} else if (cmd == 0x05 || cmd == 0x06) {
value = pwm_get_duty_cycle(); // Если да, получаем текущее значение коэффициента заполнения
}
// Кодируем команду и значение в 16-битное число
uint16_t cmd_value = cmd << 12 | (uint16_t)(value * 16.0f);
// Отправляем команду через шину I2C
i2c_start(); // Начинаем передачу
i2c_write(PWM_SLAVE_ADDR << 1); // Отправляем адрес устройства
i2c_write(cmd_value >> 8); // Передаем старший байт команды
i2c_write(cmd_value & 0xFF); // Передаем младший байт команды
Serial.println("Packgae send succesfull!");
i2c_stop(); // Завершаем передачу
// Выводим информацию о команде в монитор последовательного порта
Serial.print("Sent command: 0x");
Serial.print(cmd, HEX);
Serial.print(", value: ");
Serial.print(value);
Serial.print(", data bytes: 0x");
Serial.print(cmd_value >> 8, HEX);
Serial.print(" ");
Serial.println(cmd_value & 0xFF, HEX);
}