Ultrasonic LCD Meter — Arduino Uno simulation

Ultrasonic Distance Meter with LCD2004 display on Arduino Uno

An interactive Arduino Uno circuit simulation you can run free in your browser on Velxio, by leikz.

Components

Sketch code

/*
 * 完全无库版:Grove 超声波 + LCD2004(I2C)
 * 直接操作 TWI 寄存器,不 include 任何库
 */

#define SIG_PIN   2
#define LCD_ADDR  0x27

/* ---------- 裸 I2C / TWI ---------- */
void i2cInit() {
    TWBR = 72;        // 100kHz @ 16MHz
    TWSR = 0x00;      // 预分频 = 1
}
void i2cStart() {
    TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
}
void i2cStop() {
    TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
}
void i2cWrite(byte d) {
    TWDR = d;
    TWCR = (1<<TWINT) | (1<<TWEN);
    while (!(TWCR & (1<<TWINT)));
}
void i2cSend(byte d) {
    i2cStart();
    i2cWrite(LCD_ADDR << 1);
    i2cWrite(d);
    i2cStop();
}

/* ---------- LCD 2004 ---------- */
void lcdByte(byte val, bool isData) {
    byte rs = isData ? 0x01 : 0x00;
    i2cSend((val & 0xF0) | rs | 0x08 | 0x04);
    i2cSend((val & 0xF0) | rs | 0x08);
    i2cSend(((val<<4) & 0xF0) | rs | 0x08 | 0x04);
    i2cSend(((val<<4) & 0xF0) | rs | 0x08);
    delayMicroseconds(50);
}
void lcdCmd(byte c)  { lcdByte(c, false); }
void lcdData(byte d) { lcdByte(d, true);  }

void lcdInit() {
    delay(50);
    lcdCmd(0x30); delay(5);
    lcdCmd(0x30); delayMicroseconds(150);
    lcdCmd(0x30); delayMicroseconds(150);
    lcdCmd(0x20); delayMicroseconds(150);
    lcdCmd(0x28);
    lcdCmd(0x0C);
    lcdCmd(0x06);
    lcdCmd(0x01);
    delay(2);
}

void lcdPos(byte col, byte row) {
    static byte off[] = {0x00, 0x40, 0x14, 0x54};
    lcdCmd(0x80 | (col + off[row]));
}

void lcdStr(const char* s) { while (*s) lcdData(*s++); }

/* ---------- 超声波 ---------- */
long readCm() {
    long sum = 0;
    long minUs = 99999, maxUs = 0;
    for (byte i = 0; i < 5; i++) {
        pinMode(SIG_PIN, OUTPUT);
        digitalWrite(SIG_PIN, LOW);
        delayMicroseconds(2);
        digitalWrite(SIG_PIN, HIGH);
        delayMicroseconds(10);
        digitalWrite(SIG_PIN, LOW);
        pinMode(SIG_PIN, INPUT);
        long us = pulseIn(SIG_PIN, HIGH, 50000UL);
        if (us == 0) return -1;
        sum += us;
        if (us < minUs) minUs = us;
        if (us > maxUs) maxUs = us;
        delay(15);
    }
    long avg = (sum - minUs - maxUs) / 3;
    long cm = (long)(avg / 58.0 + 2.0);
    if (cm < 3) cm = 2;        // 传感器最小量程 2cm,再近就钳位
    return cm;
}

void setup() {
    i2cInit();
    lcdInit();
    lcdPos(0, 0);
    lcdStr("Ultrasonic Meter");
}

void loop() {
    long cm = readCm();
    lcdPos(0, 1);
    if (cm < 0) lcdStr("Out of range    ");
    else {
        char buf[16];
        snprintf(buf, sizeof(buf), "%ld cm            ", cm);
        lcdStr(buf);
    }
    delay(200);
}

More projects by leikz