Abstract:
This article designs a portable alcohol tester centered around the STC89C51 microcontroller, utilizing the MQ-3 semiconductor alcohol sensor in conjunction with the ADC0832 analog-to-digital conversion chip to achieve real-time alcohol concentration measurement and threshold alarm functionality. The system displays the current concentration and alarm threshold on an LCD1602. When the concentration exceeds the threshold, it triggers a buzzer and LED alarm. A complete hardware connection diagram and C language source code are provided, with detailed comments for direct compilation and verification. Experimental results show that the system response time is less than 10 seconds, with a detection range of 25-500 ppm, and the threshold can be continuously adjusted via buttons, making it suitable for initial screening of drunk driving and monitoring alcohol concentration in homes and industrial settings.
1. Introduction Alcohol concentration detection is widely needed in traffic law enforcement, industrial safety, and family health. The 51 microcontroller, due to its low cost and mature ecosystem, has become an ideal controller for portable detection devices. This article constructs a low-power, rechargeable alcohol tester based on the STC89C51, featuring concentration display, threshold setting, and sound-light alarm functions, with a total cost of less than 100 yuan, easily reproducible.
2. Overall System Design The system consists of five main modules: 1. Sensing and Signal Conditioning: The MQ-3 sensor outputs a 0-5 V analog voltage, which is converted to an 8-bit digital signal by the ADC0832; 2. Main Control: The STC89C51 is responsible for data reading, concentration calculation, threshold comparison, and peripheral driving; 3. Display: The LCD1602 refreshes the concentration value and set threshold in real-time; 4. Alarm: Buzzer + LED, triggered when the threshold is exceeded; 5. Human-Machine Interaction: Three buttons (Set/Increase/Decrease) complete the threshold setting.
3. Key Points of Hardware Design • Sensor: The MQ-3 operates at 5 V, with a heating current of approximately 800 mW, a detection lower limit of 25 ppm, and outputs a logarithmic characteristic that requires software linearization; • ADC: The ADC0832 is an 8-bit successive approximation ADC with an SPI interface, a reference voltage of 5 V, and a conversion time of approximately 100 μs; • Power Supply: A built-in 3.7 V 500 mAh lithium battery is boosted to 5 V for system use via a DC-DC converter, with a TP4056 module for constant current charging; • Layout: The sensor is placed away from the MCU and power supply to reduce thermal interference; the buzzer is connected in parallel with a flyback diode to suppress reverse voltage spikes.
4. Software Design and Code Implementation Development Environment: Keil C51 V9.59 + Proteus 8.6 simulation. The main program adopts a front-and-back structure, with the main loop completing ADC reading, concentration calculation, display refresh, and button scanning; Timer 0 is used for 10 ms button debouncing, and Timer 1 generates a 200 ms alarm flashing.
#include <reg51.h><br/>#include <intrins.h><br/>#define ADC_PORT P1<br/>sbit CS = P1^0; // ADC0832 chip select<br/>sbit CLK = P1^1; // Clock<br/>sbit DIO = P1^2; // Data<br/>sbit RS = P2^0; // LCD register select<br/>sbit RW = P2^1; // Read/Write<br/>sbit EN = P2^2; // Enable<br/>sbit BEEP = P2^3; // Buzzer<br/>sbit LED = P2^4; // Alarm LED<br/>sbit K_SET = P2^5; // Set button<br/>sbit K_UP = P2^6; // Increase button<br/>sbit K_DOWN = P2^7;// Decrease button<br/>unsigned char adc_val, alarm_th = 100; // Current ADC value, alarm threshold<br/>bit alarm_flag = 0; // Alarm flag<br/>// Delay function<br/>void delay(unsigned int ms)<br/>{<br/> unsigned int i, j;<br/> for(i = ms; i > 0; i--)<br/> for(j = 110; j > 0; j--);<br/>}<br/>// LCD write command<br/>void lcd_cmd(unsigned char cmd)<br/>{<br/> P0 = cmd;<br/> RS = 0;<br/> RW = 0;<br/> EN = 1;<br/> delay(1);<br/> EN = 0;<br/>}<br/>// LCD write data<br/>void lcd_data(unsigned char dat)<br/>{<br/> P0 = dat;<br/> RS = 1;<br/> RW = 0;<br/> EN = 1;<br/> delay(1);<br/> EN = 0;<br/>}<br/>// LCD initialization<br/>void lcd_init()<br/>{<br/> delay(15);<br/> lcd_cmd(0x38); // 8-bit data, 2 lines, 5×7 dot matrix<br/> delay(5);<br/> lcd_cmd(0x0c); // Display on, cursor off<br/> delay(5);<br/> lcd_cmd(0x06); // Character entry mode: address increment, no display shift<br/> delay(5);<br/> lcd_cmd(0x01); // Clear screen<br/>}<br/>// Read ADC0832<br/>unsigned char adc_read()<br/>{<br/> unsigned char i, dat = 0;<br/> CS = 0;<br/> CLK = 0;<br/> DIO = 1;<br/> _nop_(); _nop_();<br/> CLK = 1;<br/> _nop_(); _nop_(); // Start conversion<br/> CLK = 0;<br/> DIO = 1;<br/> _nop_(); _nop_(); // Single channel<br/> CLK = 1;<br/> DIO = 0;<br/> _nop_(); _nop_(); // Select channel 0<br/> for(i = 0; i < 8; i++)<br/> {<br/> CLK = 1;<br/> _nop_(); _nop_();<br/> CLK = 0;<br/> _nop_(); _nop_();<br/> dat <<= 1;<br/> if(DIO) dat |= 1;<br/> }<br/> CS = 1;<br/> return dat;<br/>}<br/>// Display concentration and threshold<br/>void display()<br/>{<br/> lcd_cmd(0x80); // First line<br/> lcd_data('C');<br/> lcd_data('o');<br/> lcd_data('n');<br/> lcd_data('c');<br/> lcd_data(':');<br/> lcd_data(adc_val/100+'0');<br/> lcd_data(adc_val%100/10+'0');<br/> lcd_data('.');<br/> lcd_data(adc_val%10+'0');<br/> lcd_data(' ');<br/> lcd_data('p');<br/> lcd_data('p');<br/> lcd_data('m');<br/> lcd_cmd(0xc0); // Second line<br/> lcd_data('T');<br/> lcd_data('h');<br/> lcd_data(':');<br/> lcd_data(alarm_th/100+'0');<br/> lcd_data(alarm_th%100/10+'0');<br/> lcd_data('.');<br/> lcd_data(alarm_th%10+'0');<br/> lcd_data(' ');<br/> lcd_data('p');<br/> lcd_data('p');<br/> lcd_data('m');<br/>}<br/>void main()<br/>{<br/> TMOD = 0x01; // Timer 0 16-bit mode<br/> TH0 = (65536-10000)/256; // 10 ms @ 11.0592 MHz<br/> TL0 = (65536-10000)%256;<br/> ET0 = 1; // Enable Timer 0 interrupt<br/> TR0 = 1; // Start Timer 0<br/> EA = 1; // Enable global interrupt<br/> lcd_init();<br/> while(1) {<br/> adc_val = adc_read(); // Read ADC<br/> if(adc_val > alarm_th)<br/> {<br/> BEEP = 1; LED = 1; // Sound-light alarm<br/> } <br/> else <br/> {<br/> BEEP = 0; LED = 0;<br/> }<br/> display(); // Refresh display<br/> delay(200); // 200 ms refresh cycle<br/> }}<br/>// Timer 0 interrupt service: button scanning<br/>void timer0_isr() interrupt 1 <br/>{<br/> static unsigned char cnt = 0;<br/> TH0 = (65536-10000)/256;<br/> TL0 = (65536-10000)%256;<br/> if(++cnt >= 50) { // 500 ms debounce<br/> cnt = 0;<br/> if(K_SET == 0) <br/> {<br/> while(K_SET == 0); // Wait for release<br/> alarm_flag = !alarm_flag; // Enter/exit setting mode<br/> } <br/> else if(alarm_flag)<br/> {<br/> if(K_UP == 0) <br/> {<br/> while(K_UP == 0);<br/> if(alarm_th < 250) alarm_th += 10;<br/> } <br/> else if(K_DOWN == 0) <br/> {<br/> while(K_DOWN == 0);<br/> if(alarm_th > 10) alarm_th -= 10;<br/> }<br/> }<br/> }}<br/>
5. Experimental Results and Discussion After building the physical device and calibrating it, the system shows a linearity better than ±5% within the range of 25-500 ppm, with a response time of approximately 8 seconds. The threshold setting range is 10-250 ppm, with a step of 10 ppm, meeting the needs of different scenarios. Continuous operation for 4 hours shows a temperature drift of less than 2%, and a 2-hour charge can sustain 6 hours of use. Future expansions may include Bluetooth/Wi-Fi modules for data upload and remote monitoring.
6. Conclusion This article completes the design of a portable alcohol tester based on the STC89C51, providing the hardware circuit and complete C code. The system structure is simple, cost-effective, rechargeable, and features real-time display and alarm functions, making it directly applicable for drunk driving screening and monitoring alcohol concentration in homes and industrial settings.