ok so i tried to make this project with code that was made from manipulating register instead of using (digitalWrite, digitalRead, AnalogRead, etc.) due to my teachers rules.
so i tried wrote the code for both master and slave (it's using I2C as serial communication that sends data (1-6) from master to slave in order to determine which motor direction will move in slave part), i'm using arduino nano for this project, but i encountered this problem (data that sends from master's part keep sending '0' even though i'm using interrupt service routine (ISR)).
here's the code that i wrote, i hope someone could help me out of this, thanks in advance!
Master's Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
volatile bool button1Pressed = false;
volatile bool button2Pressed = false;
volatile bool button3Pressed = false;
volatile bool button4Pressed = false;
volatile bool button5Pressed = false;
volatile bool button6Pressed = false;
volatile int data = 0;
long last_time = 0;
long debounce_delay = 100;
ISR(PCINT2_vect) {
if ((PIND >> 4 & 0b00010000 >> 4) == 1){
if(millis() - last_time >= debounce_delay){
button1Pressed = !button1Pressed;
data = 1;
last_time = millis();
}
}
else if ((PIND >> 5 & 0b00100000 >> 5) == 1){
if(millis() - last_time >= debounce_delay){
button2Pressed = !button2Pressed;
data = 2;
last_time = millis();
}
}
else if ((PIND >> 6 & 0b01000000 >> 6) == 1){
if(millis() - last_time >= debounce_delay){
button3Pressed = !button3Pressed;
data = 3;
last_time = millis();
}
}
else if ((PIND >> 7 & 0b10000000 >> 7) == 1){
if(millis() - last_time >= debounce_delay){
button4Pressed = !button4Pressed;
data = 4;
last_time = millis();
}
}
}
ISR(PCINT0_vect) {
if ((PINB >> 0 & 0b00000001 >> 0) == 1){
if(millis() - last_time >= debounce_delay){
button5Pressed = !button5Pressed;
data = 5;
last_time = millis();
}
}
else if ((PINB >> 1 & 0b00000010 >> 1) == 1){
if(millis() - last_time >= debounce_delay){
button6Pressed = !button6Pressed;
data = 6;
last_time = millis();
}
}
}
void setup() {
// Inisialisasi komunikasi I2C
Wire.begin();
PCICR |= (1 << PCIE2)|(1<<PCIE0); //enable untuk portB dan D
PCMSK2 |= (1 << PCINT20) | (1 << PCINT21) | (1 << PCINT22) | (1 << PCINT23);
PCMSK0 |= (1 << PCINT0) | (1 << PCINT1);
// Inisialisasi pin tombol sebagai input dengan pull-up resistor
DDRD &= ~(1 << DDD4) | ~(1 << DDD5) | ~(1 << DDD6) | ~(1 << DDD7);//input D4-D7
PORTD |= (1 << PD4 | 1 << PD5 | 1 << PD6 | 1 << PD7);//pull-up resistor
DDRB &= ~(1 << DDB0) | ~(1 << DDB1); //input D8&D9
PORTB |= (1 << PB0 | 1 << PB1); //pull-up resitor
// Mengatur interrupt untuk tombol
sei();
Serial.begin(9600); // Initialize serial communication for debugging
}
void loop() {
// Mengirim data melalui I2C jika tombol ditekan
Wire.beginTransmission(SLAVE_ADDRESS);
Wire.write(data);
Wire.endTransmission();
Serial.print("terkirim: ");
Serial.println(data); // For debugging
delay(500);
}
slave's code:
#include <Wire.h>
const uint8_t ALAMAT_SLAVE = 0x04;
uint16_t A0_adc, A1_adc;
uint16_t duty_cycle1, duty_cycle2;
#define MOTOR1IN1 PD4
#define MOTOR1IN2 PD5
#define MOTOR2IN3 PD6
#define MOTOR2IN4 PD7
#define MOTOR1ENA PB1 //OC1A (D9)
#define MOTOR2ENB PB2 //OC1B (D10)
volatile int perintahditerima = 0;
void setupPWM() {
// Configure Timer1 for Phase Correct PWM with ICR1 as TOP
TCNT1 = 0;
TCCR1A = 0;
TCCR1B = 0;
// Non-inverting PWM
TCCR1A |= (1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);
// set mode 10 (phase correct PWM TOP = ICR1) prescaler = 64
TCCR1B |= (1<<WGM13)|(1<<CS11)|(1<<CS10);
ICR1 = 2499; // f = 50 Hz (20 ms pulse)
}
void eksekusiperintah(int karakter) {
switch (karakter) {
case 1:
Motor1berhenti();
break;
case 2:
putarMotor1CW();
break;
case 3:
putarMotor1CCW();
break;
case 4:
Motor2berhenti();
break;
case 5:
putarMotor2CW();
break;
case 6:
putarMotor2CCW();
break;
}
}
void Motor1berhenti() {
PORTD &= ~((1 << MOTOR1IN1) | (1 << MOTOR1IN2)); //IN1&IN2 LOW
OCR1A = 0; // Disable Motor1 by setting PWM to 0
}
void putarMotor1CW() {
PORTD |= (1 << MOTOR1IN1);//IN1 high
PORTD &= ~(1 << MOTOR1IN2);//IN2 low
// OCR1A is already set in loop()
}
void putarMotor1CCW() {
PORTD &= ~(1 << MOTOR1IN1); //IN1 low
PORTD |= (1 << MOTOR1IN2); //IN2 high
// OCR1A is already set in loop()
}
void Motor2berhenti() {
PORTD &= ~((1 << MOTOR2IN3) | (1 << MOTOR2IN4)); //IN3&IN4 low
OCR1B = 0; // Disable Motor2 by setting PWM to 0
}
void putarMotor2CW() {
PORTD |= (1 << MOTOR2IN3); //IN3 high
PORTD &= ~(1 << MOTOR2IN4); //IN4 low
// OCR1B is already set in loop()
}
void putarMotor2CCW() {
PORTD &= ~(1 << MOTOR2IN3); //IN3 low
PORTD |= (1 << MOTOR2IN4); //IN4 high
// OCR1B is already set in loop()
}
int adc_init(void) {
ADMUX |= (1<<REFS0);
ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADEN)|(1<<ADIE);
sei();
ADCSRA |= (1 << ADSC);
}
void setup() {
// inisialisasi I2C sebagai penerima
Wire.begin(ALAMAT_SLAVE);
Wire.onReceive(ReceiveEvent);
// Set motor pins as output
DDRD |= (1 << MOTOR1IN1) | (1 << MOTOR1IN2) | (1 << MOTOR2IN3) | (1 << MOTOR2IN4);
DDRB |= (1 << MOTOR1ENA) | (1 << MOTOR2ENB); // Set pin enable as output
setupPWM();
adc_init();
sei(); // Enable global interrupts
Serial.begin(9600);
}
void loop() {
// konversi analog kepwm
int duty_cycle1 = map(A0_adc, 0, 1023, 0, 255);
int duty_cycle2 = map(A1_adc, 0, 1023, 0, 255);
OCR1A = duty_cycle1; // Set PWM for Motor1 Enable
OCR1B = duty_cycle2; // Set PWM for Motor2 Enable
eksekusiperintah(perintahditerima); //menggerakkan arah motor
// Debugging output
Serial.print("Karakter: ");
Serial.println(perintahditerima);
Serial.print("\nPot1: ");
Serial.print(A0_adc);
Serial.print(" PWM1: ");
Serial.println(duty_cycle1);
Serial.print("Pot2: ");
Serial.print(A1_adc);
Serial.print(" PWM2: ");
Serial.println(duty_cycle2);
delay(100);
}
void ReceiveEvent() {
while (1 < Wire.available()) {
perintahditerima = Wire.read();
}
}
ISR(ADC_vect){
uint16_t x = ADCW;
switch(ADMUX){
// baca ADC0
case 0x40:
A0_adc = x;
ADMUX = 0x41;
break;
// baca ADC1
case 0x41:
A1_adc = x;
ADMUX = 0x42;
break;
default:
break;
}
// mulai kembali konversi ADC
ADCSRA |= (1 << ADSC);
}