Iam beginner in arduino sketch ,
I try to write sketch based on attiny85 & lcd1602 its take 1 month
.
Now i want switch to oled ssd1306 128x32 .
But i have trouble because diferent I2C .
This my sketch with lcd 1602 bit banging , maybe someone can help me build the sketch switch to oled with same function.
`#include <avr/io.h>
#include <util/delay.h>
#include <math.h>
// Pin definisi
#define SDA PB0
#define SCL PB2
#define ADC_PIN A3 // PB3 / ADC3
#define PWM_PIN PB4 // PWM manual
#define FAN_PIN PB1
// Konstanta NTC
#define R_FIXED 10000.0
#define R25 15000.0
#define BETA 3950.0
#define T0 298.15
// Hysteresis thresholds
#define HYSTERESIS_HIGH 50.1 // Batas aktifkan over-temp
#define HYSTERESIS_LOW 48.0 // Batas nonaktifkan over-temp
// Variabel global
float prevTemp = 25.0;
float smoothedTemp = 25.0;
bool overTemp = false;
// === Bit-banging I2C ===
void i2c_start() {
digitalWrite(SDA, LOW);
_delay_us(5);
digitalWrite(SCL, LOW);
}
void i2c_stop() {
digitalWrite(SDA, LOW);
digitalWrite(SCL, HIGH);
_delay_us(5);
digitalWrite(SDA, HIGH);
_delay_us(5);
}
void i2c_write(uint8_t data) {
for (uint8_t i = 0; i < 8; i++) {
digitalWrite(SDA, (data & 0x80));
data <<= 1;
digitalWrite(SCL, HIGH);
_delay_us(5);
digitalWrite(SCL, LOW);
}
pinMode(SDA, INPUT);
digitalWrite(SCL, HIGH);
_delay_us(5);
digitalWrite(SCL, LOW);
pinMode(SDA, OUTPUT);
}
// === LCD I2C ===
#define LCD_ADDR 0x27
void lcd_command(uint8_t cmd) {
uint8_t hi = cmd & 0xF0, lo = (cmd << 4) & 0xF0;
for (uint8_t i = 0; i < 2; i++) {
uint8_t d = (i == 0) ? hi : lo;
i2c_start();
i2c_write(LCD_ADDR << 1);
i2c_write(d | 0x0C);
i2c_write(d | 0x08);
i2c_stop();
}
_delay_ms(2);
}
void lcd_data(uint8_t chr) {
uint8_t hi = chr & 0xF0, lo = (chr << 4) & 0xF0;
for (uint8_t i = 0; i < 2; i++) {
uint8_t d = (i == 0) ? hi : lo;
i2c_start();
i2c_write(LCD_ADDR << 1);
i2c_write(d | 0x0D);
i2c_write(d | 0x09);
i2c_stop();
}
_delay_us(50);
}
void lcd_init() {
_delay_ms(50);
lcd_command(0x33);
lcd_command(0x32);
lcd_command(0x28);
lcd_command(0x0C);
lcd_command(0x06);
lcd_command(0x01);
_delay_ms(10);
}
void lcd_setCursor(uint8_t col, uint8_t row) {
lcd_command(0x80 | (col + (row * 0x40)));
}
void lcd_print(const char* s) {
while (*s) lcd_data(*s++);
}
void lcd_clear_row(uint8_t row) {
lcd_setCursor(0, row);
for (uint8_t i = 0; i < 16; i++) lcd_data(' ');
}
// === Suhu dari NTC ===
float readTemperature() {
int adc = analogRead(ADC_PIN);
float v = adc / 1023.0;
float r = R_FIXED * (1.0 / v - 1.0);
float invT = 1.0 / T0 + (1.0 / BETA) * log(r / R25);
return (1.0 / invT) - 273.15;
}
// PWM manual dengan delay manual, ~1ms default period
void pwm_manual(float duty_percent, uint16_t period_us = 1000) {
if (duty_percent < 0) duty_percent = 0;
if (duty_percent > 100) duty_percent = 100;
uint8_t duty = (uint8_t)(duty_percent * 2.55); // 0β255
uint16_t delay_steps = period_us / 255;
for (uint8_t i = 0; i < 255; i++) {
if (i < duty) PORTB |= (1 << PWM_PIN);
else PORTB &= ~(1 << PWM_PIN);
for (uint16_t d = 0; d < delay_steps * 4; d++) { __asm__ __volatile__("nop"); }
}
}
void splash_screen() {
lcd_setCursor(0, 0);
lcd_print(" INTELLIGENCE ");
lcd_setCursor(0, 1);
lcd_print("TEMP CONTROLLED");
for (uint8_t i = 0; i < 35; i++) _delay_ms(100);
lcd_command(0x01);
}
void setup() {
pinMode(SDA, OUTPUT);
pinMode(SCL, OUTPUT);
pinMode(ADC_PIN, INPUT);
pinMode(FAN_PIN, OUTPUT);
pinMode(PWM_PIN, OUTPUT);
digitalWrite(FAN_PIN, LOW);
lcd_init();
splash_screen();
}
void loop() {
float temp = readTemperature();
smoothedTemp = smoothedTemp * 0.5 + temp * 0.5;
// Logika hysteresis
if (smoothedTemp >= HYSTERESIS_HIGH) {
overTemp = true;
} else if (smoothedTemp <= HYSTERESIS_LOW) {
overTemp = false;
}
float pwm = 0;
if (overTemp) {
pwm = 100;
digitalWrite(FAN_PIN, HIGH);
} else if (smoothedTemp >= 30 && smoothedTemp < HYSTERESIS_HIGH) {
pwm = 25 + (smoothedTemp - 30) * (75.0 / 20.0);
digitalWrite(FAN_PIN, LOW);
} else {
digitalWrite(FAN_PIN, LOW);
}
pwm_manual(pwm);
// Baris 1
char tbuf[10];
dtostrf(smoothedTemp, 5, 1, tbuf);
lcd_setCursor(0, 0);
lcd_print("Temp: ");
lcd_print(tbuf);
lcd_print(" C ");
// Baris 2 anti-flicker
static bool lastOverTemp = false;
static int lastPwmInt = -1;
if (overTemp != lastOverTemp || (int)pwm != lastPwmInt) {
lcd_clear_row(1);
lcd_setCursor(0, 1);
if (overTemp) {
lcd_print("!! LIMIT WARNING ");
} else {
char pbuf[10];
dtostrf(pwm, 5, 1, pbuf);
lcd_print("PWM = ");
lcd_print(pbuf);
lcd_print(" % ");
}
lastOverTemp = overTemp;
lastPwmInt = (int)pwm;
}
_delay_ms(250);
}`
