马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
单片机方向的 C 语言学习,和普通教材里的语法练习不同:代码最终要控制 LED、蜂鸣器、LCD 或传感器。只背语法容易出现“看得懂例题,但不会写项目”。下面结合单片机报警程序整理期末复习重点。 一、变量和数据类型
3 G- u9 s* W/ F6 C程序需要保存传感器采样值、计数值、延时时间和报警状态。常见写法是: - unsigned int gas_value;3 ]9 O1 X2 f/ _: @/ P
- unsigned char count;
3 r2 c) s9 [3 L9 B: i+ z& L+ U& Z1 L - bit alarm_state = 0;
复制代码unsigned char 适合保存 0~255 的小整数,unsigned int 常用于 ADC 采样值和计数值,bit 适合保存开关量。不要为了方便把所有变量都定义成 float,8 位单片机中浮点运算会增加资源消耗。 二、条件判断是报警程序的核心" O- S: V4 n J: z
- if(gas_value >= 650)! l9 i4 J+ O% ~2 E; F
- {+ Q; ?: Z7 ~& P
- BEEP = 0;7 K5 K+ ^7 P( j. N
- LED_ALARM = 0;
' b; ^9 p: C: M8 e+ H* C) Z0 _ - }4 S* B8 b4 S, D. R/ ]: w
- else
) O$ C; k, f6 e# N' V! M% J4 W - {
1 d, A% B& q* o+ t+ P$ f: h. D - BEEP = 1;; H) S4 u4 T. @0 k: Z
- LED_ALARM = 1;! S! j! L: I$ m4 a5 O
- }
复制代码需要注意,部分电路采用低电平有效方式,代码中的 0 不一定代表关闭,1 也不一定代表打开。因此端口逻辑必须结合原理图确认。建议将输出动作封装成函数。 - void alarm_on(void)7 B+ K" V6 ^5 [$ u0 S8 p) P
- {& b: o( ^! `; ~
- BEEP = 0;
- Y/ f2 `* [& T% m% v - LED_ALARM = 0;
# a; X _4 X6 r* G) z - RELAY = 0;
* V2 S4 f/ K1 b/ N _& t" ` - }, d1 u1 i6 U1 A. s( `
- & `2 c% }$ G0 t, G g
- void alarm_off(void)
5 T* ?" A1 l) v! Z" ^3 [6 K0 X - {7 i. V* H' u4 f; S9 E
- BEEP = 1;$ g' o# J8 v- E( G
- LED_ALARM = 1;6 |! q0 d" J5 l3 q
- RELAY = 1;
/ W$ y7 K9 l3 F/ C - }
复制代码 三、while 循环和主程序结构( O' e! X$ b X. l8 t
- void main(void)4 k% a$ b3 R: F
- {
% t2 a' a2 p, H& x0 x& P3 [ - system_init();
& x, G( C8 y5 j; w - while(1)* E \3 C2 a/ v& A0 Q1 k! q5 g
- {9 D5 B/ ~7 _. Q) K
- gas_value = adc_read();; E% B0 w" M1 p1 F. p5 L
- lcd_display(gas_value);3 Z P4 B2 _: R
- gas_check(gas_value);
% i6 x& l4 ^ Y6 Z - delay_ms(100);3 g% d' X+ t- J! Z4 l
- }
1 B" g$ A, a8 {; ]7 u5 q - }
复制代码主循环一般可以拆成读取、显示、判断和等待四步。没有 while(1) 时,程序只会检测一次,仿真中会表现为数值不再更新。 四、函数封装, ?6 L& k$ k3 f
建议把 LCD 初始化、ADC 读取、报警控制和延时分别写成函数。这样主程序更清晰,出错时也容易定位。 - void lcd_init(void);
* n R# {2 k3 B4 i" l; o0 l; j - void lcd_display(unsigned int value);
% Z7 Q {. s6 e- E" w- \; w! F - unsigned int adc_read(void);
$ D) B# D3 L& }: D" r8 ] - void alarm_on(void);4 U- |3 v7 j' {1 j( E& U0 @
- void alarm_off(void);3 _. x' `4 e! l5 p8 }
- void delay_ms(unsigned int ms);
复制代码 五、数组和字符串
9 v' A( Q0 i& z# K5 c' g: K- unsigned char message[] = "GAS WARNING";
5 E; X7 l* B P3 ~
: y& q! ^3 G* Y- void lcd_show_string(unsigned char row,$ F" k6 O) N1 I2 u
- unsigned char col,
, P0 _* G# H* s5 \& Q8 Y' M5 w - unsigned char *str)
' P& M8 R" P- n$ v- \% o - {7 i, A) c- y/ i8 O+ U7 O) g! S
- while(*str != 0)! p) g2 i+ f- b; N, E+ ^
- { v" Y! |1 N/ z4 K& c5 M0 l
- lcd_write_data(*str);* |' h' A2 ~. A
- str++;
. i- E( L$ [) Y1 l# I4 o - }
" a' c6 m9 @& q' C/ k- x u1 v - }
复制代码 # f) o) T) D4 R$ r
字符串以 '\0' 结束。忘记结束标志时,程序可能继续读取后面的内存内容,造成 LCD 显示乱码。 六、ADC 采样值处理
9 }8 t# O' F: Z2 [8 ^& O4 m) v- unsigned int adc_read(void)6 ?: a+ ^: a6 a% a
- {
& H1 n8 S1 Y' Q( u1 |+ t7 t - unsigned int value;
+ \9 S& b$ m" l - ADC_START = 1;$ ]8 U3 l& I5 V9 k7 e$ {
- delay_us(10);
/ P) s; T/ h8 H5 `, W4 l0 B - ADC_START = 0;, `2 [+ J2 T/ c
- while(ADC_BUSY);
/ } ?) `7 o7 j6 Y" e7 ` U% y$ A" v - value = ADC_HIGH;
3 f( Q4 K5 E& m$ p- t0 P8 x - value = (value << 8) | ADC_LOW;
* `: y- n: r) p% X. N& ]/ P - return value;
% Y+ x; g! l2 z6 d ~- {2 I - }
复制代码 3 [) O7 M& {- c4 Y6 D5 q, c; |
如果 ADC 是 10 位,数字范围通常是 0~1023;如果是 8 位,范围通常是 0~255。复习时必须先确认 ADC 位数,不能直接套用公式。 七、常见错误
7 _2 Y/ F! l8 ]( z% t3 \第一,把赋值写成比较:if(alarm_flag = 1) 是赋值,应写成 if(alarm_flag == 1)。第二,变量未初始化就参与判断。第三,忽略端口有效电平。第四,LCD 未初始化就调用显示函数。第五,延时参数过大导致程序长时间停在延时函数中。 八、综合例题& `2 q$ c$ ~ W7 X& v: y% n1 O
题目:读取气体传感器,当检测值大于 650 时启动蜂鸣器和红色 LED,否则关闭报警。 - $ v! ~5 L$ m& u3 H' U; F n
- #define GAS_LIMIT 6504 N# o7 z8 q6 J/ d8 P9 A0 y( Q6 w* f
- sbit BEEP = P2^0;0 N# [9 W! w9 S' x9 [; b$ H
- sbit LED_RED = P2^1;$ }8 ~3 ?+ Y! O' x
, w: l( Z3 V7 L& V# @* E- void main(void), ~0 K, i+ G& B4 F
- {# U' N' K( m" t+ H
- unsigned int gas_value;
3 p4 d/ G% _/ ? e0 N% c7 O - lcd_init();2 m4 D( o2 `/ s, Q& ]7 l9 z8 }- p9 J
- BEEP = 1;( }- l! u3 g. M! e k
- LED_RED = 1;
$ u3 r6 U. z. k" D* | - while(1); z7 v9 X. b8 i$ N% F4 `* V, V
- {
& ~4 |8 ]5 Q: i: m3 ` - gas_value = adc_read();
: ~$ L' K( R2 h6 E9 n - lcd_display(gas_value);5 `' b. b }" P& p9 s
- if(gas_value >= GAS_LIMIT)4 p/ P- M) F% |" H3 e1 i
- {
% `. {2 O1 b3 F6 ` - BEEP = 0; LED_RED = 0;
! e7 b9 [9 x6 R! v `% a- v' |$ a* d! a) e - lcd_show_string(1, 1, "DANGER");( \9 x$ A3 V: U
- }
* a+ t- r4 J5 Q$ l X! u - else; ~) ?* p, }' |5 Q2 i
- {
[/ r1 `% b& [* V - BEEP = 1; LED_RED = 1;
, Q. k6 [& I6 O8 j* _ - lcd_show_string(1, 1, "SAFE ");- g: C* ]& E# L8 C; S8 x
- }4 {4 c% f/ z4 T4 ?5 j6 ^, i
- delay_ms(200);$ T8 I1 x5 r2 X
- }
2 d& \' k3 B' S8 y1 M - }
复制代码 ) w) u# a$ r; R0 G1 x
九、复习建议8 {4 ^6 r6 ]& O; }. f/ J
单片机 C 语言不适合只背定义,建议按照“语法—代码—仿真现象”的顺序复习。复习 if...else 时同步看报警控制程序,复习函数时分析 LCD 初始化,复习数组和字符串时结合 LCD 显示。遇到错误时,通过仿真现象反推问题位置。 总结
6 x* V2 I- v" \9 H7 d单片机方向的 C 语言重点集中在变量、条件判断、循环、函数、数组、端口控制和传感器数据处理。真正写项目时,难点不是单个语法,而是把多个知识点组合成“采集—判断—显示—执行”的完整流程。
. a; b# \3 t6 r4 ^0 N- U3 ~8 B
2 Z0 `: l7 m$ r& }, h( G3 D |