8.Master_I2C_PWM/main2.cpp
2023-06-21 17:22:44 +03:00

183 lines
5.1 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.

#include <avr/io.h>
#include <stdint.h>
#include <util/delay.h>
#define I2C_FREQ 100000UL
#define F_CPU 16000000UL
#define I2C_PRESCALER 1
#define I2C_BITRATE ((F_CPU / I2C_FREQ) - 16) / (2 * I2C_PRESCALER)
#define I2C_READ 1
#define I2C_WRITE 0
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 address, const uint8_t* data, uint8_t length) {
i2c_start();
// Отправляем адрес устройства с битом записи
TWDR = address << 1 | I2C_WRITE;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
for (uint8_t i = 0; i < length; i++) {
TWDR = data[i];
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
}
i2c_stop();
}
void i2c_read(uint8_t address, uint8_t* data, uint8_t length) {
i2c_start();
// Отправляем адрес устройства с битом чтения
TWDR = address << 1 | I2C_READ;
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
for (uint8_t i = 0; i < length; i++) {
// для всех байт, кроме последнего - отправляем ACK
if (i < length - 1) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
while (!(TWCR & (1 << TWINT)));
data[i] = TWDR;
}
// для последнего байта - отправляем NACK
else {
TWCR = (1 << TWINT) | (1 << TWEN);
while (!(TWCR & (1 << TWINT)));
data[i] = TWDR;
}
}
i2c_stop();
}
#define F_CPU 16000000UL
void pwm_init() {
TCCR1A |= (1 << COM1A1) | (1 << WGM11); // non-inverting mode, Fast PWM (mode 14)
TCCR1B |= (1 << WGM12) | (1 << WGM13) | (1 << CS10); // Fast PWM (mode 14), prescaler = 1
DDRB |= (1 << PB1); // set pin PB1 as output
}
void pwm_set_frequency(uint16_t frequency) {
uint16_t prescaler = 1;
uint32_t top = F_CPU / (prescaler * frequency) - 1;
ICR1 = top;
}
void pwm_set_duty_cycle(float dutyCycle) {
uint16_t value = ICR1 * dutyCycle / 100.0;
OCR1A = value;
}
void pwm_enable() {
pwm_set_duty_cycle(50); // Начальная скважность
}
void pwm_disable() {
pwm_set_duty_cycle(0); // Выключение ШИМ
}
void i2c_init();
void i2c_start();
void i2c_stop();
void i2c_write(uint8_t address, const uint8_t* data, uint8_t length);
void i2c_read(uint8_t address, uint8_t* data, uint8_t length);
void pwm_init();
void pwm_set_frequency(uint16_t frequency);
void pwm_set_duty_cycle(float dutyCycle);
void pwm_enable();
void pwm_disable();
const uint8_t BUTTON_PIN[] = {0, 1, 2, 3, 4, 5};
const uint8_t PWM_SLAVE_ADDR = 9;
uint16_t command = 0x00;
float frequency = 1000.0;
float dutyCycle = 50.0;
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); // включение подтягивающего резистора
}
void loop() {
// Обработка нажатий на кнопки
checkButton(0, 0x01, 0.0);
checkButton(1, 0x02, 0.0);
checkButton(2, 0x03, 1.25);
checkButton(3, 0x04, 0.8);
checkButton(4, 0x05, 1.1);
checkButton(5, 0x06, 0.9);
}
void checkButton(uint8_t pin, uint16_t cmd, float value) {
if (bit_is_clear(PINC, pin)) {
sendCommand(cmd, value);
if (cmd == 0x03) {
frequency *= value;
pwm_set_frequency(frequency);
} else if (cmd == 0x04) {
frequency *= value;
pwm_set_frequency(frequency);
} else if (cmd == 0x05) {
dutyCycle *= value;
pwm_set_duty_cycle(dutyCycle);
} else if (cmd == 0x06) {
dutyCycle *= value;
pwm_set_duty_cycle(dutyCycle);
} else if (cmd == 0x02) {
pwm_disable(); // Выключение ШИМ
} else if (cmd == 0x01) {
pwm_enable(); // Включение ШИМ
}
command = cmd;
_delay_ms(500); // Задержка для антидребезга
}
}
void sendCommand(uint16_t cmd, float value) {
uint16_t data = (uint16_t)(value * 16.0);
data |= cmd << 4;
uint8_t buffer[2];
buffer[0] = data >> 8;
buffer[1] = data & 0xFF;
i2c_write(PWM_SLAVE_ADDR, buffer, 2);
Serial.print("Command: ");
Serial.print(cmd);
Serial.print(", Value: ");
Serial.println(value, 4);
}