#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/adc.h"
#include "hardware/pwm.h"
#include "hardware/i2c.h"
#include "hardware/gpio.h"
// ── 传感器 / 外设 ───────────────────────────────
#define PIN_PIR 2
#define PIN_TRIG 4
#define PIN_ECHO 3
#define ADC_PIN 26
#define PIN_LED_RED 17
#define PIN_LED_GRN 16
#define PIN_BUZZER 12
// ── I²C LCD (HD44780 + PCF8574) ────────────────
#define I2C_PORT i2c0 // 改成 i2c0 若用 GP8/GP9
#define PIN_LCD_SDA 8
#define PIN_LCD_SCL 9
#define LCD_ADDR 0x27
#define LCD_COLS 20
#define LCD_ROWS 2 // 16×2 就写 2
// PCF8574 输出位
#define LCD_RS 0x01
#define LCD_RW 0x02
#define LCD_EN 0x04
#define LCD_BL 0x08 // 背光常亮
// —— 简易 I²C 写 & LCD 基本操作 ————————————————
static inline void lcd_i2c(uint8_t v){ i2c_write_blocking(I2C_PORT,LCD_ADDR,&v,1,false); }
static void lcd_pulse(uint8_t v){ lcd_i2c(v|LCD_EN); sleep_us(1); lcd_i2c(v&~LCD_EN); sleep_us(50); }
static void lcd_send(uint8_t d,uint8_t mode){
uint8_t h=(d&0xF0)|mode|LCD_BL, l=((d<<4)&0xF0)|mode|LCD_BL;
lcd_i2c(h); lcd_pulse(h); lcd_i2c(l); lcd_pulse(l);
}
static void lcd_cmd(uint8_t c){ lcd_send(c,0); }
static void lcd_chr(char c){ lcd_send(c,LCD_RS); }
static void lcd_print(const char *s){ while(*s) lcd_chr(*s++); }
static const uint8_t row_ofs[4]={0x00,0x40,0x14,0x54};
static void lcd_pos(uint8_t r,uint8_t c){ lcd_cmd(0x80|(row_ofs[r]+c)); }
static void lcd_init(void){
sleep_ms(50);
for(int i=0;i<3;i++){ lcd_i2c(0x30|LCD_BL); lcd_pulse(0x30|LCD_BL); sleep_ms(5); }
lcd_i2c(0x20|LCD_BL); lcd_pulse(0x20|LCD_BL); sleep_ms(5);
lcd_cmd(0x28); lcd_cmd(0x08); lcd_cmd(0x01); sleep_ms(2);
lcd_cmd(0x06); lcd_cmd(0x0C);
}
// —— 业务参数 ————————————————————————————————
const float DIST_TH = 50.0f; // cm
const uint16_t LIGHT_TH = 2000; // ADC
const uint32_t PERIOD = 500; // ms
// —— 蜂鸣器 ——
static void beep(uint32_t ms){
uint s=pwm_gpio_to_slice_num(PIN_BUZZER);
pwm_set_clkdiv(s,125.0f); pwm_set_wrap(s,999);
pwm_set_chan_level(s,pwm_gpio_to_channel(PIN_BUZZER),500);
pwm_set_enabled(s,true); sleep_ms(ms); pwm_set_enabled(s,false);
}
// —— 超声波测距 ——
static float distance_cm(void){
gpio_put(PIN_TRIG,0); sleep_us(2); gpio_put(PIN_TRIG,1);sleep_us(30);gpio_put(PIN_TRIG, 0);
absolute_time_t t0=get_absolute_time(), tout=delayed_by_ms(t0,50);
while(!gpio_get(PIN_ECHO))
if(absolute_time_diff_us(get_absolute_time(),tout)>=0) return DIST_TH*2;
absolute_time_t t1=get_absolute_time(); tout=delayed_by_ms(t1,50);
while(gpio_get(PIN_ECHO))
if(absolute_time_diff_us(get_absolute_time(),tout)>=0) break;
int64_t us=absolute_time_diff_us(t1,get_absolute_time());
return us*0.01715f;
}
int main(){
stdio_init_all();
// — GPIO / ADC —
gpio_init(PIN_PIR); gpio_set_dir(PIN_PIR,GPIO_IN);
gpio_init(PIN_TRIG); gpio_set_dir(PIN_TRIG,GPIO_OUT); gpio_put(PIN_TRIG,0);
gpio_init(PIN_ECHO); gpio_set_dir(PIN_ECHO,GPIO_IN);
adc_init(); adc_gpio_init(ADC_PIN); adc_select_input(0);
gpio_init(PIN_LED_RED); gpio_set_dir(PIN_LED_RED,GPIO_OUT); gpio_put(PIN_LED_RED,0);
gpio_init(PIN_LED_GRN); gpio_set_dir(PIN_LED_GRN,GPIO_OUT); gpio_put(PIN_LED_GRN,0);
gpio_set_function(PIN_BUZZER,GPIO_FUNC_PWM);
// — I²C & LCD —
i2c_init(I2C_PORT,400000); // 400 kHz
gpio_set_function(PIN_LCD_SDA,GPIO_FUNC_I2C);
gpio_set_function(PIN_LCD_SCL,GPIO_FUNC_I2C);
gpio_pull_up(PIN_LCD_SDA); gpio_pull_up(PIN_LCD_SCL);
lcd_init();
bool last_occ=false; char buf[21];
while(true){
// 1) 读传感器
bool pir=gpio_get(PIN_PIR);
float dist=distance_cm();
uint16_t lux=adc_read();
bool occ=pir || (dist<DIST_TH);
// 2) 状态边沿
if(occ && !last_occ){ gpio_put(PIN_LED_RED,1); gpio_put(PIN_LED_GRN,0); beep(100); }
else if(!occ && last_occ){ gpio_put(PIN_LED_RED,0); gpio_put(PIN_LED_GRN,1); beep(50); sleep_ms(50); beep(50); }
last_occ=occ;
// 3) 光照反馈
if(lux<LIGHT_TH) gpio_xor_mask(1u<<PIN_LED_GRN);
else if(!occ) gpio_put(PIN_LED_GRN,0);
// 4) 刷 LCD
lcd_cmd(0x01); // 清屏
lcd_pos(0,0); snprintf(buf,20,"PIR:%s Dist:%04.1f",pir?"Y":"N",dist); lcd_print(buf);
lcd_pos(1,0); snprintf(buf,20,"Lux:%u %s",lux,occ?"OCCUPIED":"EMPTY"); lcd_print(buf);
#if LCD_ROWS>2
lcd_pos(2,0); snprintf(buf,20,"Thr D:%2.0f L:%u",DIST_TH,LIGHT_TH); lcd_print(buf);
#endif
sleep_ms(PERIOD);
}
}