1 概述* d3 d/ l8 L4 l+ ^/ J& g: |
1.1 资源概述
+ g( l+ L9 d6 Q9 V0 _开发板:正点原子STM32F103 Nano开发板
( ^; t1 C; W1 s* F. gCUBEMX版本:1.3.0
, z$ J+ q9 V; x+ _* f5 y0 PMDK版本:5.231 P2 P$ @, \( l5 L+ u+ K
主控芯片型号:STM32F103RBT6
. C! O+ C. J* h7 Z5 N. U" j% D2 k
& V4 `0 x2 j& |% m- } S: i% t
5 i; c* m$ ]" ~/ l9 N6 m, D; {, ? n" B
1.2 实现功能" \5 Y$ x" y1 W& X
1 本实验开机进入等待红外触发,如过接收到正确的红外信号,则解码,并在数码管上显示;1 G* i! N( p( w3 R/ b7 v3 G9 F8 k
2 按键1-7分别控制LED1-LED7,电源按键用来打开所有的LED1-LED7,外星人按键用来关闭所有的LED1-LED7;5 _9 I0 W: K1 [
3 另外将按键判定从定时器中断中分离出来,放在main函数中;
) K" |2 D0 R: I; y0 r6 j6 a$ O4 使用vol-,开启和关闭声音;6 K' g e$ v4 y( J, w
5 使用开发板上的key1按键用来保存声音的配置,保存的数据写入iic中,这样重新上电或者复位后可以使用;& N2 k; L( i; F' f. G2 E6 `" b
6 LED0用来指示程序的运行状态。
5 r* O# c2 W2 P# b- q. K5 _3 k9 y; p' o
2 硬件相关知识
5 T# [" u, i& o2 E. `2.1电路图2 Y1 x# X1 |' g- }! h7 j
采用38译码器和移位寄存器实现。
4 z( i4 c: `2 z5 B7 J/ o, ?8 w
) ?+ m; X0 w3 S
* a. l' u$ i# v6 M. D9 U' Z6 e: ?' d: V; L0 m6 X- J7 }
2.2 字符查询3 A- b* Z, P' D: c9 p
字符查询,极性是共阴,排列顺序是a-dp$ w1 l( W+ w5 ~& U
! P( `+ ~# ^; b- w3 s
1 _+ u) ]7 G1 V' c# ?1 d- C& F) a. n7 K0 S
tips: v# a- N3 E7 R5 t1 J9 K
如果我们要实现小数点,有一个捷径,不用重新生成字符,在原来字符上增加一个或0x01(共阴adp方式)的操作,如H.代码为0x6e|0x01
' Q. X! c8 D: X' [
8 R6 d5 g2 ]5 t7 G" D# [
$ ^& N0 x! p5 u g* e
2 c7 h2 C c* o2 ]3 程序实现) }1 {/ i) I: t- ?8 R9 n
此程序在正点原子的红外实验程序基础上进行修改,增加了IIC程序,用来保存按键声音的配置。通常在工程中,使用EEPROM来保存配置信息,这样掉电就不会消失。最常用的是各种设置信息的保存。还有一些ADC的校准信息,程序版本信息等,都会保存在IIC中。! A6 ]. O7 p! }1 R5 K
实现的逻辑思想
5 Z0 G1 M+ T* U1 k9 x: I5 P. W1、进入main程序,读取IIC中声音的配置变量;! a, [8 G& X" ?: w( u6 f3 R$ ]; j/ c
2、依据声音配置变量,设置按键声音开还是关;
9 p( k) W* C4 n* O8 Q# Z7 G3、扫描远程遥控器按键,并作出对应的操作;
3 J- q" l# O) D4、扫描本地按键,如果key1被按下,则写IIC,保存声音配置。1 ~- ]5 k% A# a5 ]) z* R' I7 x
在主程序中,使用了字符串赋值函数strcpy,以及字符串比较函数strcmp,因此在头文件中需要包含头文件string.h,由于对按键赋值使用到了true和false,因此使用到了bool型变量,需要包含头文件stdbool.h。
) h0 S1 r) M3 A( C程序进行了改写,将定时器中断中的按键检测挪到了主函数中,中断中不宜进行太多的逻辑操作。- ]: A2 a9 i# k$ x, A
程序中增加了一个250ms翻转一次的LED灯,用来当做“心跳”,当程序卡死或者异常时,此灯的状态会表现异常,这也是一种很常见的工程方法。7 {7 i z* u+ E7 L, C
" ?( R6 m2 \6 s* V. h参数保存还有优化的空间,最佳的方式是在下电过程中进行保存,而不是人工保存,这样能减少EEPROM的写入次数,延长EEPROM的寿命,通常EEPROM的寿命只有几千次。
+ M9 ?% @& e+ `' G' z* x
6 C; T) p1 w& Z' h1,主程序代码如下# _% d7 G& j* w+ G# L" j) @$ T
6 T% c7 |3 d+ a+ W0 b' X; x) }" [, t
- #include "sys.h"
* q, b- k0 q9 I* v - #include "delay.h"! `1 R2 ]% R! k( h! m" w- c
- #include "usart.h"
; d( M( P5 y; e9 q - #include "led.h"# C. K& y+ ~4 |. T
- #include "smg.h"
' W$ D( s ^7 U$ m2 e - #include "remote.h" * z% ^6 J3 l `. r- r; Z+ H1 a3 ]
- #include "timer.h"
. T4 Z/ S1 O# G; w - #include "beep.h"
- w( U6 Z+ h5 Z6 N. d& e3 T8 S - #include <stdbool.h>
7 V$ _: v) B8 X! u# V2 O - #include "24cxx.h" # l' ^8 S6 m/ a6 w2 j
- #include "myiic.h"! Q2 Y# v7 h# `! q& H7 B9 O- J
- #include "key.h"
3 q$ B# q5 {" L2 t - #include <string.h>( t/ y- x( O9 h- B
+ m+ f! c! F* a1 b- // 共阴数字数组
0 c7 R4 T- c* P% D2 l7 M - // 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, .,全灭# T( ? s+ n3 r. g3 ~! q
- u8 smg_num[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,0xee,0x3e,0x9c,0x7a,0x9e,0x8e,0x01,0x00};
' m$ y( b$ i; P* c* l' ` - u8 keyRemote=0,keyLocal = 0;; //按键值
; T7 w5 f/ q: y8 {# k* ] - u8 num=0x00;//数值6 G1 `6 o6 o% g, R
- u8 num1=0x00;//数值 p& j# @# E& ^% K# E' a
- u8 smg_wei=6;//数码管位选
7 [1 `- j7 B# M9 Y' A% l) `* f - u8 smg_duan=0;//数码管段选
: ]$ C$ v) G, Z. y5 e5 { - u8 smg_flag=0;//数码管显示标志 0:正常显示 1:消除鬼影; m, y. Q' D1 D( D
- u8 t=0;
- a( {4 @, X* f6 y( h - char TEXT_Buffer[]={"NANO STM32 IIC TEST"};; ~ s) ]0 _ c7 g1 }: N) E; e
- #define SIZE sizeof(TEXT_Buffer)
( o/ ^/ a& n. C" s6 Q* m -
. p* i; Q# V2 R: E" W$ K I - int main(void)
, H/ F# ?& U1 T! _/ e - {
+ d% u& J) s: v! V& e - bool volState = false ;//true为关闭声音,false为打开声音9 E1 M7 z' s- `* z3 X2 v( R$ Y: H* T
- char datatemp[SIZE];! t' k/ X) E- {" _; p2 f" m" [6 Y
-
- H- e* [8 c/ x* d& @ - HAL_Init(); //初始化HAL库
( H: q m. _8 ]' ?$ i7 S2 a - Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
; r- I' d. N' C& p/ \+ D: E, g - delay_init(72); //初始化延时函数
. o1 e* ~; F: N# V0 r5 \) o R - uart_init(115200); //串口初始化为115200
* i' B K. h) N$ g - LED_Init(); //初始化与LED连接的硬件接口
( F+ z0 i+ Z2 V6 A6 S, C9 l - BEEP_Init(); //蜂鸣器初始化
3 ]& |6 g9 R+ A8 W" _0 H, x - LED_Init(); //初始化与LED连接的硬件接口
* h n+ r5 q% j& d1 l* J! v - LED_SMG_Init(); //数码管初始化
% c; P; L; m% K - TIM4_Init(19,7199); //数码管2ms定时显示' u# a, T4 I: B) l
- Remote_Init(); //红外接收初始化 & n! r+ g( y, A2 e2 N2 y# ]" J q) f
- AT24CXX_Init(); //IIC初始化 9 L3 g" U0 _! i4 p- E' I" {1 I5 w8 m
- KEY_Init(); //按键初始化
: G1 y; z3 H8 L) ]4 K - if(AT24CXX_Check())//检测不到24c02( _* ]1 \5 j+ B- {( \2 i: w8 r* }. t
- {6 p' ]; F% q2 j B
- printf("24C02 Check Failed!\r\n");
. m, E6 R0 |/ p - delay_ms(500);4 Y3 L0 F& B+ N$ y3 d, x$ X
- printf("Please Check!\r\n");7 P( T. \. R/ J8 t7 C
- delay_ms(500);9 n4 ~1 Z# V# k# P7 f7 ]" v3 l
- LED0=!LED0;//DS0闪烁' {, p. M2 y: x1 T1 X% F( T8 C
- }4 Y5 C9 \% C( y: [5 {$ o
- else# V; i8 p0 `7 {& y2 M
- printf("24C02 Ready!\r\n");( K0 _7 L" [7 B$ B
- printf("WK_UP:save the volume setting!\r\n");//显示提示信息
3 i, C6 ]# u: m" i! A" M - printf("1-7:led1-LED7 switch\r\n");# ^" ^) i) y s+ J
- printf("power:all led off\r\n");. M( w$ h1 i1 C) W, R0 ~6 [
- printf("alientec:all led on\r\n");
- K( e Y0 y% O+ t, Y - printf("vol-:sound switch\r\n");
7 }7 l: p3 u: h- l! I) c% D5 L - AT24CXX_Read(0,datatemp,SIZE);
! k9 G3 d, J) @3 T" F - printf("The Data Readed Is:\r\n");//提示传送完成! n+ N& l2 d! Y
- printf("%s\r\n",datatemp);//显示读到的字符串
4 P, i; p- p5 ] F. |' o* w: x - * G( Y6 l8 t* y
- if(strcmp(datatemp,"true"))' |0 H/ k# T- H
- volState = false ;
3 s% F& e9 d( W/ ?9 | - else
" M- P, x# d6 m* J; m/ m4 H - volState = true ;1 i: b9 `) x: W" o! @& x
# V, |2 m+ u+ a' v9 ?0 o7 e- + }' X, j5 z. v) e4 X! `
- while(1)
' {' C, L7 t2 k! O1 R# u - {
6 d/ r. X B1 Q+ v - keyRemote = Remote_Scan();
; m% e3 }' D: R) s4 U% c - if(keyRemote)
) t+ K! |7 {3 I! _6 _ - {
8 `0 O. C5 ]) ^. P - switch(keyRemote); h) [6 S x0 |- u
- {
' V Q; _. B L - case 104:
( U" a( ]5 d9 t0 \* n - num1=0x00; num = smg_num[1]; BEEP=volState;
2 r" u2 [/ B6 I - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_1);
, ^1 O/ S3 K' j1 x; |& U7 o' u$ O; ? - break; //按键'1'
* E" e! X0 G7 q% w4 K - case 152:
; P F8 _( T# p- @( G) S - num1=0x00;num=smg_num[2];BEEP = volState;
. k* W0 P% [% |4 @2 w - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_2);
/ ~! H, O' \+ R& L* u0 B0 M7 J - break; //按键'2'
1 ~( s6 d) q: c - case 176:
# b( i/ m- h# Z6 [; O0 L6 u4 | - num1=0x00;num=smg_num[3];BEEP = volState;6 A3 h" E T: ^0 W- {
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_3);( }! l2 A3 m4 p1 g
- break; //按键'3'
- F: ^* v* r: h - case 48:
! d1 z; t2 S" g! p" k5 C - num1=0x00;num=smg_num[4];BEEP = volState;
- w' j% T$ c- q1 v - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_4);7 r Q7 h6 N( h* X/ Q
- break; //按键'4'
; O& Y! i+ ^+ Y% I) J& _% | - case 24:
7 m" r( r: R$ X# B5 m- s - num1=0x00;num=smg_num[5];BEEP = volState;" ?, b) i# w* U. }% F3 q
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_5);
1 I, ~/ F7 u3 }0 v1 U7 x: S - break; //按键'5' & p: F4 i2 G0 Y* H( I
- case 122:6 }# k$ a0 a1 Y) G2 H; e" n$ S
- num1=0x00;num=smg_num[6];BEEP = volState;
5 s3 {5 t1 V, ?3 v$ t8 v8 u* w - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_6); P# W; ?/ T; U: Z1 C5 o6 u
- break; //按键'6'
) W( x$ q* ]" s( X6 ]! ] - case 16:; M6 \% t: J! x9 z( U. p
- num1=0x00;num=smg_num[7];BEEP = volState;: Q9 R& R2 w2 ?( l3 `0 I
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_7); 3 N7 `4 y l' H0 v1 K1 n9 |
- break; //按键'7' # H) H$ k, @6 x! q$ j8 f
- case 56:num1=0x00;num=smg_num[8];BEEP = volState;break; //按键'8' 3 a( b. X, F9 s2 l2 d( a% y' L
- case 90:num1=0x00;num=smg_num[9];BEEP = volState;break; //按键'9'
1 E7 f6 K' _. F - case 66:num1=0x00;num=smg_num[0];BEEP = volState;break; //按键'0'* N/ g" Z$ \/ m( E$ {7 m. ?
- case 82:num1=0x00;num=smg_num[17];BEEP = volState;break; //按键'DELETE'% a! \* w N2 J7 J; E4 n
- case 162:' E- V' r. W1 f r; D$ E8 s
- num1=smg_num[1];num=smg_num[0];BEEP = volState; + n# X+ S* g5 Q% ~2 t2 H
- HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|
5 [2 G' \5 n9 J1 [* l$ |( m+ T - GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_PIN_SET); //PC0~7置1,灯灭
" I. \3 i7 p1 ]' Z - break;//按键'POWER'
2 E0 p) k5 k8 A) F - case 98:num1=smg_num[1];num=smg_num[1];BEEP = volState; break;//按键'UP'$ A2 P( V( \5 B3 T+ J
- case 226:
Z- L, E* ^* d1 e- u) g - num1=smg_num[1];num=smg_num[2];BEEP = volState;
* ~0 o. Z. Q" ]% Q1 i3 q - HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|
4 U* ?0 B3 w! `7 ^: q - GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_PIN_RESET); //PC0~7置0,灯开
- K% Y5 T$ } `! o, |, m, m - break;//按键'ALIENTEK'6 _$ x, J+ ^# {. F: [% i1 X
- case 34:num1=smg_num[1];num=smg_num[3];BEEP = volState; break;//按键'LEFT'1 e0 [2 m& {3 M3 N/ w
- case 2:num1=smg_num[1];num=smg_num[4];BEEP = volState; break;//按键'PLAY'2 ^. o1 Q7 b* w0 h( [4 Y
- case 194:num1=smg_num[1];num=smg_num[5];BEEP = volState; break;//按键'RIGHT'- i T z: X# a; |
- case 224:
! ]: S0 j' l& h( l$ D - num1=smg_num[1];num=smg_num[6];BEEP = 0;
5 b) D. v O" ?8 M1 ^ - volState = !volState;' X+ f2 s+ }; y7 j
- break;//按键'VOL-'
# I. [5 y" C l5 R6 J: }; N9 P - case 168:num1=smg_num[1];num=smg_num[7];BEEP = volState; break;//按键'DOWN') c4 l( ]( z3 \. A! P. X+ N+ r( `9 b
- case 144:num1=smg_num[1];num=smg_num[8];BEEP = volState; break;//按键'VOL+'( f* d' i% [, l- J
- }
' l+ h6 [4 S% o - }else
) M% x+ X, U/ _ I4 P - {* \ Z7 A4 g9 Q- u. Q
- BEEP=1;, `) h& ~) r1 t* |
- }& {: h( x0 Q U6 @8 q9 ?
$ y9 d& Z3 p# L8 m- if(volState)
d4 K1 i' Z" T5 e5 e" z% k$ Y - strcpy(TEXT_Buffer,"true");
3 L1 r; z& C. {8 ^) V% t; I - else/ r' R6 ^' a1 N( P
- strcpy(TEXT_Buffer,"false");; e- Y3 M3 y& Y
-
- D& ~/ u B6 P0 V9 k$ s) m) m - keyLocal=KEY_Scan(0);2 ~3 b9 Z# S% c. @" `& A+ j' ^
- if(keyLocal==WKUP_PRES)//WK_UP 按下,写入24C02- x4 R4 M" l0 O0 K
- {
# Q" }" F0 f" J0 ~ - printf("\r\nStart Write 24C02....\r\n");, X$ x: h9 ~. C7 L
- AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);
2 F( M+ w9 K2 h, i - printf("24C02 Write Finished!\r\n");//提示传送完成
8 c# U* {. W% }; `: Z - printf("\r\nStart Read 24C02....\r\n");1 B8 U& R$ S5 k( H5 ]
- AT24CXX_Read(0,datatemp,SIZE);
+ U* d$ n+ H& W# H - printf("The Data Readed Is:\r\n");//提示传送完成
" o& ?: V, x& S; V6 ~ - printf("%s\r\n",datatemp);//显示读到的字符串: J' P6 V( L6 \- ]! c. t. k
- }
+ E) U4 i: N* d4 H g - 9 V- R* [% \% Y4 k
-
N. g: j9 c6 ?& x) p# S" C+ u& I, m& m, M - HAL_Delay(1);( X: i2 T( l' s) U* {$ h' m
- t++;: W& `/ Y% [$ H4 I
- if(t==250)//LED0每500MS闪烁
% P) [, | c0 X' J6 s - {
$ K% O" [1 A E9 x% |2 Z+ Z6 @ - t=0;
' v" w2 S8 N) { - LED0=!LED0;9 n% H; N; v ^; A" q
- }
" a" {% h4 G3 ~7 T2 h# | - } ' b/ s+ s2 T' z3 f; R
- }' l0 F+ j' v# `0 c5 P! K
2 q' n0 Z; T# m: q2 |
/ e" t/ a e, c/ ? t- //定时器4中断服务函数调用
$ [9 l. b* y3 L5 H1 f$ h - void TIM4_IRQHandler(void)9 ~7 k. x- z2 m1 {7 |
- {
( I: Y2 R. b( j" O/ d% ?, D - if(__HAL_TIM_GET_IT_SOURCE(&TIM4_Handler, TIM_IT_UPDATE) !=RESET)
6 d5 r7 W% m# V! E% g! l3 J - {- X7 S' ~: O3 F: A' c
- __HAL_TIM_CLEAR_IT(&TIM4_Handler, TIM_IT_UPDATE);2 N! _6 z; X9 \ Y( Z% q
, ?; T0 g" I. d; G/ G" ]- }
- @. m5 j7 c' D - if(smg_wei==6)//数码管位
$ Q% f1 n K" w9 b - {/ [ n3 w5 L) ~& P# @3 n. k3 a$ a
- smg_duan = num1;
$ p8 B$ R7 u* `7 E6 ?2 A: ^9 t - }
6 u. ~: ]0 E& B, M& H - else if(smg_wei==7)7 ]7 ^6 ?9 P( T0 m% r- `) K
- {
9 O0 }7 \: p( f% v - smg_duan = num;5 c2 E& j8 y/ i7 ]: m9 {, u# X; q
- }, V+ v3 T; H% j( B) k
- if(smg_flag)
/ h$ L1 t! w4 o% }5 l" G! [ - LED_Write_Data(0x00,smg_wei);//消除鬼影(段码不显示) W/ y- {- M4 A- K
- else 6 P, d- ?6 w- y( ]
- LED_Write_Data(smg_duan,smg_wei);//正常显示
) v5 [8 x/ F- m- i& ? - LED_Refresh();//数码管数据更新
( D/ H0 r E& N% [/ N$ p8 T - smg_flag=!smg_flag;* n+ Y$ \$ W; @+ L$ D
- if(smg_flag==0)//正常显示才更新位码
E6 B" R4 r$ B, U1 W& S - {+ N, i* X% Q" h
- smg_wei++;2 M$ X+ l1 b3 ?
- if(smg_wei==8) smg_wei=6;
' M' b/ l; g: I, w9 \ - }
5 a9 M" r7 \. ^: Y - }
复制代码
- ?8 A: L* j6 Q* m" ]3 s. e4 实验结果% V L% S, B2 z) J
实验结果如下,所有逻辑操作正确
0 p$ z/ b$ E* h2 }) R0 |. Q; [, {2 _" m: k: G9 E! c
J4 a% S+ N% Z
2 l, p& m0 I R+ `串口显示信息,声音按键设置可以正常保存,复位或者断电重启后并不会消失。; }$ m) }2 T( v0 B( e7 ]. O
6 R. {4 J& e5 G% e K. b
( b6 {2 F. z% F0 [2 b& o+ { w( O
5 额外的TIPS
% R* i0 a5 m4 v* e5 ?1 E, Z7 h调整LED亮度的几种方式
$ @0 I* f# S; m9 x( J1,电路方法:减小限流电阻阻值,从而增大LED的电流,达到增加亮度目的。
# y- ]* D' A5 j( O2 c" t2,软件方法:增加LED在单位时间内的总亮时长,方式有两种,增加刷新频率以及增大单个刷新周期内的点亮时间。0 V+ K" u2 g5 f- Y4 s1 j1 s. o
3,物理方法:如果LED有透光保护膜,增加透光膜的透明度。
2 m# t" g+ S; T* H5 A0 x3 C
8 b n& z) e# P* [) ?& s$ s0 {( F% O( K, H4 Z2 g7 F
|