1 概述
! c; ^7 G1 v$ f5 Z9 X- @, K$ q1.1 资源概述' p; k' O% e q- B X. d& d
开发板:正点原子STM32F103 Nano开发板- H5 @" w; U: M1 G; r' r" r
CUBEMX版本:1.3.0
0 S; X4 v2 x9 R C6 }$ w+ NMDK版本:5.23
- g3 x/ H! G- i: x主控芯片型号:STM32F103RBT6
. P3 d9 c4 I& D' P5 T: Q
! ?6 B, G: `: l/ E: W+ m1 A
! [( {6 K6 W7 M
' b- U" {2 q k) ~) C% r1 [: H2 b* j5 `1.2 实现功能' ]3 P% c# ] ~ _
1 本实验开机进入等待红外触发,如过接收到正确的红外信号,则解码,并在数码管上显示;
$ c( l6 X) A$ X, G. @- v% x: I$ _2 按键1-7分别控制LED1-LED7,电源按键用来打开所有的LED1-LED7,外星人按键用来关闭所有的LED1-LED7;- f, h' P/ L# v! l2 g; s7 p9 r
3 另外将按键判定从定时器中断中分离出来,放在main函数中;7 \6 t6 x" `( O9 \1 D1 d0 A& J# u
4 使用vol-,开启和关闭声音;
: i1 H4 F: I) D- q \; |5 使用开发板上的key1按键用来保存声音的配置,保存的数据写入iic中,这样重新上电或者复位后可以使用;* Y @' w% _$ t
6 LED0用来指示程序的运行状态。, Y' ?0 W T9 s! S4 W
7 s$ J/ ~# S8 x" `2 硬件相关知识. r9 L% F: ` c9 p- k$ V
2.1电路图6 X6 b+ |3 v- o
采用38译码器和移位寄存器实现。
( T( e6 F1 G2 A) @- k. F* O9 w; s+ Z" _
1 v% B+ [3 N' k- V: g3 y. B5 Q5 ~8 d$ s/ D8 \7 z/ d4 u# `% x
2.2 字符查询" }1 X/ q1 Q7 K9 o* I# Z4 L3 q
字符查询,极性是共阴,排列顺序是a-dp
! K" D- C$ Q7 U H- }# c" O* K& x; H
6 g. p0 J2 z. U! `9 s7 F9 Z1 q) w7 P4 X, |" \
tips$ a, t8 |1 ]) V/ p- p
如果我们要实现小数点,有一个捷径,不用重新生成字符,在原来字符上增加一个或0x01(共阴adp方式)的操作,如H.代码为0x6e|0x01
# i0 i% E/ ~7 G1 N5 V. a7 I7 d3 h* } X4 u
: G/ b& s; j7 b7 u1 l
D0 V! N" `0 h; ?" o1 S9 G3 程序实现
X( Z' @9 e6 j3 V& m此程序在正点原子的红外实验程序基础上进行修改,增加了IIC程序,用来保存按键声音的配置。通常在工程中,使用EEPROM来保存配置信息,这样掉电就不会消失。最常用的是各种设置信息的保存。还有一些ADC的校准信息,程序版本信息等,都会保存在IIC中。. z! i: I4 |' y8 @3 ^
实现的逻辑思想
1 b o0 ~2 L1 x1、进入main程序,读取IIC中声音的配置变量;& i3 M8 ~& |3 N5 r5 B+ ?
2、依据声音配置变量,设置按键声音开还是关;
, H4 j) ]7 h* p3、扫描远程遥控器按键,并作出对应的操作;
_% T$ h e$ g( z' V" p' g4、扫描本地按键,如果key1被按下,则写IIC,保存声音配置。
M0 Y$ t3 N; E* |7 k1 A; L7 O0 S+ @在主程序中,使用了字符串赋值函数strcpy,以及字符串比较函数strcmp,因此在头文件中需要包含头文件string.h,由于对按键赋值使用到了true和false,因此使用到了bool型变量,需要包含头文件stdbool.h。0 n, z3 C4 D' \7 N
程序进行了改写,将定时器中断中的按键检测挪到了主函数中,中断中不宜进行太多的逻辑操作。% m+ z) k3 A7 `5 _5 D
程序中增加了一个250ms翻转一次的LED灯,用来当做“心跳”,当程序卡死或者异常时,此灯的状态会表现异常,这也是一种很常见的工程方法。
8 q" S- h: V+ v) R$ P3 ]4 J* E& W$ }; |6 B
参数保存还有优化的空间,最佳的方式是在下电过程中进行保存,而不是人工保存,这样能减少EEPROM的写入次数,延长EEPROM的寿命,通常EEPROM的寿命只有几千次。
, a& x3 n/ d0 `. X9 J9 z' J/ n% f v V$ U
1,主程序代码如下% {% q4 q) l8 y# o
/ N$ e E. w! `4 u8 |* F6 m+ |4 N
- #include "sys.h"% f. {# m- S+ F! f4 P) t% c. L
- #include "delay.h"! l2 R; a" m, q
- #include "usart.h"" o6 N' F4 H( n; L: T7 X( [, _
- #include "led.h"
[( ^. M5 q. \% b: o( S - #include "smg.h"
/ \, L" C9 d8 g0 k$ b8 {9 Y6 L - #include "remote.h"
# M* Q8 z: y- P! s; }. v - #include "timer.h"
2 S5 B! ~+ v7 ?4 T, y$ d1 `- B - #include "beep.h"% F5 Q! V% o) N1 F1 \' q# M
- #include <stdbool.h>4 }7 C. j% f2 ^! d
- #include "24cxx.h" 9 G, K2 N/ J, z; B, q5 I
- #include "myiic.h", Q' y$ U4 \4 N5 [1 Z$ m) Z- ~& i
- #include "key.h"
1 `9 u3 R) n& d& i( F - #include <string.h>. [. }9 D& v3 v5 j1 a4 h; Z$ _: k
- j% a( I; @" C4 k9 I9 T4 k- // 共阴数字数组5 d# G v1 A' E7 Q
- // 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F, .,全灭/ d( x0 O' C; w- P9 b! n
- u8 smg_num[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,0xee,0x3e,0x9c,0x7a,0x9e,0x8e,0x01,0x00};
, U L L% s, G - u8 keyRemote=0,keyLocal = 0;; //按键值, `' t% S1 x! V! n3 k Q
- u8 num=0x00;//数值
- F+ N, N' I$ V3 g" K - u8 num1=0x00;//数值# L5 @3 X0 r' }! Y
- u8 smg_wei=6;//数码管位选1 S; V: J( C& h8 \. e; D
- u8 smg_duan=0;//数码管段选
& S$ D. e6 s& e, N: { - u8 smg_flag=0;//数码管显示标志 0:正常显示 1:消除鬼影
* J# I3 ?8 V# g: C - u8 t=0; 3 g. b$ D N6 I- e2 r- _
- char TEXT_Buffer[]={"NANO STM32 IIC TEST"};
# O/ K1 k1 j) l4 h; T; | - #define SIZE sizeof(TEXT_Buffer)
# M( v# Z! Q. @ -
* B# A+ D! P6 q- R - int main(void)+ t# Y; R6 Q; G. |+ S$ T4 k
- {9 M7 ?9 L8 A% z
- bool volState = false ;//true为关闭声音,false为打开声音! c0 I& ]( U2 A1 O+ k
- char datatemp[SIZE];: K4 U- `+ x+ w$ n/ @. Z1 M
- % E# }9 g& G) x# |1 p4 B
- HAL_Init(); //初始化HAL库 , {! z4 }$ b. D, ~( t
- Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M- A8 ~/ l% q2 b, q) T* D' `
- delay_init(72); //初始化延时函数
2 Y! E% w8 Q% g; A' T8 p7 }1 c - uart_init(115200); //串口初始化为1152008 Y! D6 `2 X9 H4 Q! w
- LED_Init(); //初始化与LED连接的硬件接口
5 ?+ ]% a! z, b - BEEP_Init(); //蜂鸣器初始化
: J* m, F- k4 i9 ?; e6 M; P" d2 q - LED_Init(); //初始化与LED连接的硬件接口, S/ p+ |% C6 a$ i; x0 {- X& Z3 |
- LED_SMG_Init(); //数码管初始化$ d4 \# _8 K- P2 h! g
- TIM4_Init(19,7199); //数码管2ms定时显示5 r/ f( t' u* ^
- Remote_Init(); //红外接收初始化 % @& P: J/ d# ~. D) E' F
- AT24CXX_Init(); //IIC初始化
) b3 M3 }- B! K5 ^ |( { - KEY_Init(); //按键初始化
+ q( l8 V, Y+ R2 ` - if(AT24CXX_Check())//检测不到24c02; F, X3 H# |# A7 q
- {% E- ?- v& {4 t" C
- printf("24C02 Check Failed!\r\n");6 R* m2 X, S7 d' c5 Z0 j* j8 r) N
- delay_ms(500);: c/ G0 S. ^! c3 D2 m
- printf("Please Check!\r\n");4 P6 w8 Z: K. q8 j, G! v* U
- delay_ms(500);
' X/ ]9 \" b e5 ?# ^; l: Z - LED0=!LED0;//DS0闪烁
8 H7 I2 ~; q) X- b8 s - }( \2 ^ Y9 {, D
- else
3 {+ ^8 t* z3 I$ f. F4 l - printf("24C02 Ready!\r\n");
2 V( e% k7 h/ B, Y( D' B - printf("WK_UP:save the volume setting!\r\n");//显示提示信息 & k! v8 s8 ^7 K9 i9 `4 d/ _5 z
- printf("1-7:led1-LED7 switch\r\n");
; O: d, k/ _' |6 f; a6 d6 ~( {: E: [ - printf("power:all led off\r\n");: n7 F/ T- U! D' J' U
- printf("alientec:all led on\r\n");! ~. }5 N! N8 d0 E- y
- printf("vol-:sound switch\r\n");. v/ X# d0 R R( f
- AT24CXX_Read(0,datatemp,SIZE);+ J r5 [9 c/ ]$ D. J; q
- printf("The Data Readed Is:\r\n");//提示传送完成
: Y8 r& B3 q; u5 h3 ` - printf("%s\r\n",datatemp);//显示读到的字符串. s) b1 t2 _% t5 J- @
* }* J) G+ [6 }$ p; W- if(strcmp(datatemp,"true"))
* m% q/ D5 `6 I) g" ? - volState = false ;
8 p8 |0 }/ f. S" q9 d3 G - else / o% X/ w" z1 n3 }9 v! | r* z
- volState = true ;7 N, ]& T( ^ g0 P0 d D7 R0 O- z
; L# @; t _) o+ U- 5 S+ Y: w" M" p* t
- while(1)
2 |9 H* o; W8 f0 @7 L; J! u: u - {
/ w+ T* r- D1 Y$ O$ p. V Y - keyRemote = Remote_Scan();
; t9 i2 D5 r1 E O - if(keyRemote)9 R' T. \, i! S' P3 J
- {( o0 b" `+ H+ R3 A1 ?& V
- switch(keyRemote)
3 ^9 w( ?% w9 G8 e ?1 w - {
& F: X W; t8 y/ N4 i7 E - case 104:' |+ @* q, c. `. ]) U0 ?& E
- num1=0x00; num = smg_num[1]; BEEP=volState;' M' _, C0 E' }- Q, O3 m
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_1);. P' p7 R8 c7 Z1 [' Z( N/ K) M
- break; //按键'1'
" a! ~7 A6 Q2 u7 S# G, @ - case 152:( O, ]/ \, [' ^3 j8 L" ^
- num1=0x00;num=smg_num[2];BEEP = volState;
4 P% V3 J: O; p - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_2);
3 K: e: l o% x. k) W. u% }' P W - break; //按键'2'
' G; t: I3 a0 G) F. T1 @3 i# C - case 176:2 b# u2 }5 s# s$ J9 X- V7 |
- num1=0x00;num=smg_num[3];BEEP = volState;+ b" C( C0 `0 ~ I/ O: X% H9 s- o* l
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_3);4 E+ _, X* d# G- r5 b4 a
- break; //按键'3' ' b* C! ~8 F4 ~8 Q5 L
- case 48:
( ~' w- O, ?) o3 a6 A5 w - num1=0x00;num=smg_num[4];BEEP = volState;: X* V1 U& T$ v/ i) l3 L
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_4);
9 m5 c6 P; }/ Y! p: a7 g8 G - break; //按键'4' , r) t# A4 P5 _0 L! ^
- case 24:
% s$ ^2 r+ R% n5 | - num1=0x00;num=smg_num[5];BEEP = volState;
3 @: h1 [ C q& ]& n9 v - HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_5);
$ R7 a4 `+ V; ~7 j; k - break; //按键'5'
" u1 F! W+ y5 }3 J4 s* ]( x - case 122:( A. r n: V' h7 b9 d
- num1=0x00;num=smg_num[6];BEEP = volState;9 u& M6 ]2 I9 H R
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_6);8 U' ~* A* P7 \( o+ w: m! ~
- break; //按键'6'
: N$ a: { S5 d" z - case 16:
( f/ F" G8 L+ F) G5 u) U U - num1=0x00;num=smg_num[7];BEEP = volState;7 u1 A. k% b$ N5 a; l
- HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_7); 4 V# X( b% K+ N6 V9 @
- break; //按键'7'
. R. ]. _' c0 v% M: {! P8 o - case 56:num1=0x00;num=smg_num[8];BEEP = volState;break; //按键'8'
& \) |- K- U2 X6 F/ ~ - case 90:num1=0x00;num=smg_num[9];BEEP = volState;break; //按键'9'
6 W1 M) i$ B/ v# a3 T - case 66:num1=0x00;num=smg_num[0];BEEP = volState;break; //按键'0'/ n: ~0 H: C1 l. \2 H
- case 82:num1=0x00;num=smg_num[17];BEEP = volState;break; //按键'DELETE'
W( z; {# e8 y3 U8 T - case 162:
1 N. f0 ^/ h, ?( I* F - num1=smg_num[1];num=smg_num[0];BEEP = volState;
: _! Z4 K6 R7 K' z# Z# A - HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|1 J: `4 ~' z8 D( K! O' _
- GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_PIN_SET); //PC0~7置1,灯灭
7 Y! P) }2 |& I% S; Q - break;//按键'POWER' . _2 i! I8 I- `7 `- V/ {
- case 98:num1=smg_num[1];num=smg_num[1];BEEP = volState; break;//按键'UP'
+ e3 g* u+ b& d1 h# z4 ` - case 226:
7 k% D/ t7 M% t2 \+ } - num1=smg_num[1];num=smg_num[2];BEEP = volState;
" B8 _ B; r, s: O - HAL_GPIO_WritePin(GPIOC,GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4|3 Z0 L* W, H, u2 Q
- GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7,GPIO_PIN_RESET); //PC0~7置0,灯开/ ^3 k9 K# e8 \/ z7 {, b" Q! \/ G
- break;//按键'ALIENTEK'; K4 f& o( F8 f; s. l" f
- case 34:num1=smg_num[1];num=smg_num[3];BEEP = volState; break;//按键'LEFT'
5 {# C2 X4 A4 |, f - case 2:num1=smg_num[1];num=smg_num[4];BEEP = volState; break;//按键'PLAY'
8 {" @$ N( K4 b - case 194:num1=smg_num[1];num=smg_num[5];BEEP = volState; break;//按键'RIGHT'; B$ L( i/ v0 _ K( w+ h& [
- case 224:$ `) r3 w) o2 j/ Y! Y
- num1=smg_num[1];num=smg_num[6];BEEP = 0;; t& z0 s! _ J( M
- volState = !volState;& z) J! p/ a+ u% u% x
- break;//按键'VOL-'
8 u% A+ @% C% E7 ?7 K( ~ H - case 168:num1=smg_num[1];num=smg_num[7];BEEP = volState; break;//按键'DOWN'& y1 {+ Y1 ^( D! \' y
- case 144:num1=smg_num[1];num=smg_num[8];BEEP = volState; break;//按键'VOL+'4 u" v. i+ W2 R, G3 _
- }
5 x0 I! v8 \! S/ x - }else* A( w+ X1 P8 O6 m) i: l! c; Y; R
- {) z5 p& w: u9 I8 I4 ~
- BEEP=1;
1 B# l2 T8 @7 w* { - }% k. K$ z0 s+ P, c; V
0 [$ K8 F+ R% D3 Y# {) k* u- if(volState)3 \1 O1 J0 ?' r* C% a3 d- T7 W
- strcpy(TEXT_Buffer,"true");: C4 b! D' Y6 m% Q1 I+ l
- else
) X+ j' R5 L4 i - strcpy(TEXT_Buffer,"false");- L- \9 x1 O( V$ Z L' r: ?
- ( c/ ?& _0 u! w) N6 x) h8 D q
- keyLocal=KEY_Scan(0);; ?4 o" u4 n. P* P0 B8 N0 Z0 C, ?. t
- if(keyLocal==WKUP_PRES)//WK_UP 按下,写入24C02
, {' b& {3 z9 h; Z8 D - {( v. j. x( W( D: |% l- J6 I
- printf("\r\nStart Write 24C02....\r\n");
, H8 W) Q5 E6 V9 ?0 A& `# { - AT24CXX_Write(0,(u8*)TEXT_Buffer,SIZE);& W' w G9 r' Q. a2 @
- printf("24C02 Write Finished!\r\n");//提示传送完成
3 O, Q7 o' I6 b' L, } - printf("\r\nStart Read 24C02....\r\n");
/ D" ~- U2 b3 y" ?4 I0 L - AT24CXX_Read(0,datatemp,SIZE);; K' S4 J- Q1 \! W& f+ q8 @ y
- printf("The Data Readed Is:\r\n");//提示传送完成
_2 O9 c& ]3 m* y - printf("%s\r\n",datatemp);//显示读到的字符串
' ?4 I8 o1 T% w F - }9 a7 Z. B+ Y) e' X
- . ^: W* |/ m% ?& H3 I. s d
- + r$ L' O' z C" }5 P! G% f; U
- HAL_Delay(1);# X+ @' K# H! g& [+ B
- t++;
0 L4 R2 q* p- d1 w) G/ k0 X8 w/ Z - if(t==250)//LED0每500MS闪烁
/ a" s: T+ n/ v* I$ \; C3 ~3 M; t2 M - {
4 M, g, d, ]7 S0 i! `6 o - t=0;
* i( [' @" I1 V% T, }, X - LED0=!LED0;$ R9 i# ^" k1 N+ O
- } / X9 X3 U% ]% M6 l
- } 1 d' T2 H% m* |9 E- b# i# o+ Y3 \
- }( N; b" K( P8 ~5 n- }- Q% k1 L# q
" R* V9 s" }2 c+ v# z$ _3 Z- 4 }+ b0 w& `2 f* `7 s! Z1 W$ F
- //定时器4中断服务函数调用, m, E3 V6 Y6 R( t, U+ ~
- void TIM4_IRQHandler(void)+ S! S! ~, O9 Q: Q
- {
- N$ `& J2 Y7 T+ G5 X - if(__HAL_TIM_GET_IT_SOURCE(&TIM4_Handler, TIM_IT_UPDATE) !=RESET)( w" o5 u6 v0 o! G
- {
+ A, J( L% e; M( k' M+ C - __HAL_TIM_CLEAR_IT(&TIM4_Handler, TIM_IT_UPDATE);' z. T" H3 Z: ^% Q" V
- 3 M9 [* N: l, y d9 ? N
- }
9 m, S. K- r) S5 _- x+ P6 u. K - if(smg_wei==6)//数码管位
( I1 H/ v3 k& a2 A3 K- m0 j+ f - {/ ~/ T& K" b* [# D& }
- smg_duan = num1;5 t" i% r. Y: {5 ~- L9 q; V) D$ Q
- }8 S/ M5 L+ G! M5 n2 D& X7 H O; A W
- else if(smg_wei==7)
) N9 F0 f+ Q9 R5 q/ C - {: }9 j/ a8 I$ Y2 P
- smg_duan = num;- ?: W# c- b3 e+ @4 h8 ^
- }
2 n$ a4 r3 N! e" S - if(smg_flag)
5 U, u6 ^) }) Y9 D3 k - LED_Write_Data(0x00,smg_wei);//消除鬼影(段码不显示)4 o0 n; y# X' c# T+ I3 D4 f
- else
& I: P: H) R9 p/ j! j8 z - LED_Write_Data(smg_duan,smg_wei);//正常显示
% U* O" c7 G: \6 a3 F - LED_Refresh();//数码管数据更新4 s e. r5 r& k" D) U5 a3 T/ K
- smg_flag=!smg_flag;
. Z5 y4 {0 q0 d& | - if(smg_flag==0)//正常显示才更新位码9 W x: s, t4 e
- {
9 k$ V0 c }( K5 _2 v+ L: d. V - smg_wei++;
) F( R- P+ X. i" r8 a: M' m, P - if(smg_wei==8) smg_wei=6;
/ s% P/ X R! m' h4 i* f3 K* T - } - F, k/ U7 P- f
- }
复制代码 9 I9 y+ w5 I; M1 s4 N- C6 g3 z& H
4 实验结果2 z4 S! Q* m. g
实验结果如下,所有逻辑操作正确2 J1 _: W" K* j4 ?" X0 R( h
1 ]) {( {' T$ C, J$ g& {5 l- A3 P1 D
. z% ^5 d* A+ J8 {# D+ [0 b; E8 R, I; h( C) k
串口显示信息,声音按键设置可以正常保存,复位或者断电重启后并不会消失。
& h+ d& p! Y- I: T: r5 y% y% O- F4 c" P6 g" @9 [# f) i; I
' a2 z0 {4 M/ b. Z4 q/ r1 s8 b9 z3 m$ c+ _% J1 i
5 额外的TIPS; l: B$ o, x/ e
调整LED亮度的几种方式9 x( d3 |: a# K4 u( H7 }/ ^8 a5 O1 ~" E
1,电路方法:减小限流电阻阻值,从而增大LED的电流,达到增加亮度目的。1 O+ M7 z. ]5 Q1 q5 ^
2,软件方法:增加LED在单位时间内的总亮时长,方式有两种,增加刷新频率以及增大单个刷新周期内的点亮时间。2 B! }7 E& J q- n
3,物理方法:如果LED有透光保护膜,增加透光膜的透明度。/ i* Q2 e E3 A5 w3 d
% s/ n0 K# T4 |0 O0 O
( l! Y* ?- C8 Y
|