|
STM32学习笔记17—485通信实验
- H4 C2 n4 F. o7 b+ j6 M+ r
17.1 485协议概述 # N+ t9 Z' p) M" |
485是属于OSI模型物理层的电气标准,属于2线制,半双工,多点通信标准,485总线采用两根线路的电压差来传递信号,485两根线路名称为A和B,当线路A与线路B的电压差为+2~+6V时表示逻辑电平1,当线路A与线路B的电压差为-2~-6V时表示逻辑电平0,485与232协议都属于串口通信协议,都是采用转换芯片将USART接口电平转换为485电平或者232电平,485协议传输速率在10米时候可达35Mbps,在1200米是可达到100Kbps,最大支持总线挂载32个节点,如果采用特制的芯片可以达到400个节点。
& a0 j T u; t- g
485电气连接中,为了进行阻抗匹配,需要在两根线路中并联一个120Ω的电阻,一般是一个设备并联一个,所以485协议只是之前USART协议的另一种表现形式,通过之前掌握的USART配置,借助485转换芯片就可以完成485通信线路的搭建。
- Y! I M( v5 p* u) f. S$ ]6 `
17.2 实验例程
9 K8 g; P0 ]: i0 l1 x* h7 {3 t# }! p
采用STM32F103ZET6芯片的PA2(USART2_TXD)和PA3(USART2_RXD)和一个485转换芯片SP485来实现RS485通信。其中SP485引脚描述如下图所示。 6 U Z" d0 e1 z3 x+ \1 @6 I: G- z
: o8 A5 X. `( b$ S. l9 @* f# z) u
. M2 \; r* ]9 W) i+ [' ?- u
, K$ P. m* g9 G" V4 j(1)创建rs485.h文件,输入以下代码。 - /*********************************************************************************************************
* A2 O( L& j$ G* v V. e" _ - RS485 驱 动 文 件" j8 A/ D3 j. A: }% b% \
- *********************************************************************************************************/4 y% d% |! n+ o
- #ifndef _RS485_H_
" v2 E8 D( J) ?. k7 T9 B c! F - #define _RS485_H_
; X4 B& ^6 ]. w- n
2 Y! \1 A0 K5 P e4 I7 k B- #include "sys.h"
3 `9 y* w1 V. e3 L) \ K. c' z+ ^4 T) { - /*********************************************************************************************************
( Z' c9 P% x( r - 硬 件 端 口 定 义
* T ^! ~# B2 ?3 J3 I/ G - *********************************************************************************************************/
! g. j6 |- k" K# C - #define RS485_EN PDout( 7 )
8 R- B. c3 z. f) Q4 Q - /*********************************************************************************************************
, r* N2 Z0 `( |/ L8 K- } - 数 据 结 构 定 义
7 s: u! R- s. ]3 i) \$ W - *********************************************************************************************************/
% @! |2 d" R4 E2 | - typedef struct/ [. b; S/ \6 c# s
- {, F4 [' B6 T" s) `
- u8 Buffer[ 255 ] ;
# G2 H7 \: x( l$ b2 W+ Z - u8 Len ;/ b) M# z3 Y( C& ~* e$ z. A, M
- }Communication_Data;, z$ n4 F- H. r' x
- extern Communication_Data RS485_Data;
; j& X* B: c" T! f" |+ R - /*********************************************************************************************************6 A0 }: ?/ q, [5 d( C U' c
- 函 数 列 表7 v1 D4 ~ I$ ~8 e$ a) l& \
- *********************************************************************************************************/2 {$ ^$ b% G+ @4 d! P1 \2 `
- void RS485_Init( u32 pclk1,u32 bound ) ; //RS485初始化
# I- |! v5 s, F7 p/ \ - void RS485_Send_Data( u8 *buf, u8 len ) ; //发送n个字节) b$ l/ J+ P/ h0 P+ q/ i
- void RS485_Receive_Data( u8 *buf, u8 *len ) ; //接收n个字节
+ o. ]3 T. Q8 E3 X- L5 I - # f* c6 u, H6 Y
- #endif
复制代码 $ Q; t7 t! `. g( R% `4 o- B( ^
(2)创建rs485.c文件,输入以下代码。 - #include "rs485.h"
! y( v; T) [5 i0 H; [# F - #include "delay.h"
. h6 p2 p. e0 ]- s
" \6 X2 S- s$ H' `% j7 U+ [- Communication_Data RS485_Data;: Y W$ Z' x# i$ d% P- W7 n
- /***************************************************
& K! e' T. ?! q6 f+ o* S - Name :USART2_IRQHandler( ?! u# F2 _9 \; S
- Function :串口2中断服务函数
' ~! V. ]4 y; o0 g# D. | - Paramater :None" V6 h8 A. t: |/ |
- Return :None: V4 X- O9 C6 }7 F3 }+ n2 _
- ***************************************************/8 E, m& w0 ^9 U% X
- void USART2_IRQHandler()2 C- ~# g; G- _ m4 [/ W! ^
- {4 Y9 o0 M4 q2 a( y- ^+ z0 e& y
- //接收到数据) ?$ t% x+ ]3 e1 u* Y+ |6 O9 p
- if( USART2->SR&( 1<<5 ) )+ W0 m+ x6 N9 J! @
- {
F7 q& L O' G. |1 p/ O- \ - RS485_Data.Buffer[ RS485_Data.Len ] = USART2->DR ; //记录接收到的值4 s# |1 U5 X/ n. D
- RS485_Data.Len ++ ; //接收数据增加1
" b! K4 P, L+ W4 s X2 ` - }$ V# R1 S9 J) J: Y
- }
' b! {3 V" r1 H, E A - /***************************************************7 a; P4 ]5 \2 l9 ?9 d
- Name :RS485_Send_Data- U) A' ^' z! u7 h& u3 f- y
- Function :接收n个字节) n6 k$ n2 ^0 x ?
- Paramater :! B' J# F$ V6 ?1 H3 Q- D# F, N7 r; \
- *buf:接收区首地址
( D) r& r5 }3 j. U( B( s6 r. r - len:读取的字节数
% y6 i4 I2 R9 F - Return :None
& M' D+ s9 w" w% L( m2 | - ***************************************************/
1 j& P* U3 `6 w8 k - void RS485_Receive_Data( u8 *buf, u8 *len )
. E, N) }; W) I. q) N - {
% e* j4 H4 M3 \3 m' ~( @8 G6 m( B* O" e - u8 i, rxlen=RS485_Data.Len ;
& P% w) l2 [& Y - delay_ms( 10 ) ; //连续超过10ms没有接收到一个数据,则认为接收结束! n+ J1 U& G) |
- //接收到了数据,且接收完成了
; W( r- S/ {0 b/ N3 B4 t# W4 } - if( ( rxlen==RS485_Data.Len )&&( rxlen!=0 ) )
5 @: }0 g& k# f1 n - {) w+ e, a/ P* k! t
- for( i=0; i<rxlen; i++ )
- a& B! c2 W+ k9 q" x g! b7 F - buf[ i ] = RS485_Data.Buffer[ i ] ;% ]: V4 `# k. P* f6 c2 h1 p
- *len = RS485_Data.Len ; //记录本次数据长度
/ t4 Y' [' N1 `' K - RS485_Data.Len = 0 ; //清零3 i$ J' _! o4 K* L% D
- }
# b& m6 A% `* M. C7 [$ q - }
; O2 W' y" {9 e; A4 Q - /***************************************************' V! T3 |9 k! z8 |
- Name :RS485_Send_Data0 @( u: N% y9 w8 V% T2 T
- Function :发送n个字节* Z9 o3 K. ~3 U+ \
- Paramater :
* H; ^) O" ]2 o4 A, U+ ?; [ - *buf:发送区首地址& _$ d& P; g5 q- u, `0 A
- len:发送的字节数2 @+ M; u% \/ C" |1 w9 F. v% J5 j
- Return :None
1 i8 ]' i. z6 |% o8 C8 Y - ***************************************************/
- x- t5 A3 c) W0 f ~, J - void RS485_Send_Data( u8 *buf, u8 len )3 U1 T! g+ z4 x, d& P
- {
" o' {7 P ]! L N2 L+ ~5 u - u8 t ;) I( T; B+ \% i
- RS485_EN = 1 ; //设置为发送模式( q! [% D8 W2 k- J
- //循环发送数据
! K- Q, R. _9 D2 F: x k3 x3 C. ~: c - for( t=0; t<len; t++ ). Z% s* B) O; [- Q3 G
- {( A8 S" | o& Y; ]
- while( ( USART2->SR&0x40 )==0 ) ;//等待发送结束5 Z, t) A% I8 C; y: |
- USART2->DR = buf[ t ] ;* V9 B* [ {0 D6 ^( h* W- ?
- }
! \7 O6 C$ C% b4 [ - while( ( USART2->SR&0x40 )==0 ) ; //等待发送结束 & Y+ N1 E8 Y- y: S9 t. T
- RS485_Data.Len = 0 ;/ z) |% i- G6 b$ q/ [
- RS485_EN = 0 ; //设置为接收模式. X8 S% }4 V$ l2 @- v( p
- }
, h4 j# b5 ?1 N7 X1 C - /***************************************************' C. C! L5 `/ M! D7 t. U0 R
- Name :RS485_Init7 g% }7 o7 Y1 T5 t+ o
- Function :RS485初始化
3 s& F7 ~' i+ k4 H) j4 c6 S - Paramater :
3 O, d+ O1 \* Q2 B$ x/ }) }5 n - pclk1:PCLK1时钟频率
" G! N8 K7 k( _* z2 P6 c+ n - bound:波特率
" W3 K5 f* q) n/ O9 C - Return :None/ c \6 L; b, m% z) v
- ***************************************************/+ F; g! _5 M/ U6 f) S) ~2 L$ g6 r* V
- void RS485_Init( u32 pclk1, u32 bound )
( a8 E" l6 z4 \7 p- V2 s0 G - {8 Z$ Q- F2 t' V: G
- float temp ;
V# L! H" ]& S6 Y) v - u16 mantissa, fraction ;
5 g8 h* X% {& | - temp = ( float )( pclk1*1000000 )/( bound*16 ) ; //得到USARTDIV
" u6 Y0 |, l0 g: w4 T3 J - mantissa = temp ; //得到整数部分
& B% q# d7 S3 ~ o3 I - fraction = ( temp-mantissa )*16 ; //得到小数部分
) P( V6 u) r' ] - mantissa <<= 4 ;4 e4 M7 [, a, y
- mantissa += fraction ;* W- b6 \( F) Y/ |
- RCC->APB2ENR |= 1<<5 ; //使能PD口
9 r) T7 |* U% u - GPIOD->CRL &= 0x0FFFFFFF ;# N9 R; G2 w; B2 ]
- GPIOD->CRL |= 0x30000000 ;8 R& w* w" b( t* G: B$ H8 R
- - R; w `) ]- m: w
- RCC->APB2ENR |= 1<<2 ; //使能PA口" S( C. [1 g2 m% X2 `2 G& U
- GPIOA->CRL &= 0xFFFF00FF ; //IO状态设置
, m$ W; U( E; n# a+ ^$ U! N - GPIOA->CRL |= 0x00008B00 ; //IO状态设置0 w2 G: v! m( v8 c% S" l' ?
- RCC->APB1ENR |= 1<<17 ; //使能串口时钟
1 ?1 ?7 l) S" M+ t/ Z q - RCC->APB1RSTR |= 1<<17 ; //复位串口2
T9 k- A! _. D! C: R' A# J- A - RCC->APB1RSTR &= ~( 1<<17 ) ; //停止复位7 ~4 X( k9 T% u( ^
- //波特率设置
5 w9 A5 t6 Q3 z& Z - USART2->BRR = mantissa ; //波特率设置& v8 S( f, j/ X- [$ ^2 C
- USART2->CR1 |= 0x200C ; //1位停止,无校验位3 Q, W. r; a. v7 K7 I
- USART2->CR1 |= 1<<8 ; //PE中断使能
+ K( L+ Q; Q, j @- B, k: Y2 \ - USART2->CR1 |= 1<<5 ; //接收缓冲区非空中断使能
+ J( u5 J; {0 g5 i- C6 f8 w - NVIC_Init( 3, 3, USART2_IRQn, 2 ) ; //组27 a M! |4 w0 y$ \8 g9 a6 L
- RS485_EN = 0 ; //默认为接收模式5 G J! J- P% F
- }
复制代码 ' k" S/ i/ Y( O! ~: |4 r
(3)创建1.c文件,输入以下代码。 - #include "sys.h"; Q) `9 y1 \- ~' l! ~
- #include "delay.h"
/ E: C) A& a3 g - #include "usart1.h"8 ~" M3 S: P; q' c+ |; r$ q% F
- #include "rs485.h"( S' ]* P8 F( v3 a. [1 S- N
- 9 S7 `4 V8 @2 n' d) q4 v ~' v
- int main()0 |3 x+ R! [" F& j6 }, X
- {
$ I. p, p) K+ H8 h0 }! n0 ? - u8 len, datatemp[ 10 ] ;
! k( U4 g, @- ]# H - STM32_Clock_Init( 9 ) ; //STM32时钟初始化8 N5 z$ r5 n+ S) ?1 i' r. x/ D
- SysTick_Init( 72 ) ; //SysTick初始化4 n( ?" o, D; E7 T4 a
- USART1_Init( 72, 115200 ) ; //初始化串口1波特率1152002 ]5 x7 j; e. p# Y" O" D/ h1 q
- RS485_Init( 36, 9600 ) ; //初始化RS485
3 G; i b5 B) v, c - RS485_Send_Data( "RS485 Test", 10 ) ; //发送数据
) U' L. I9 Z( S. b5 H3 K - while( 1 )
8 h# {% k/ s9 @! N/ \' ~! Y1 Q! E - {
! d4 `% ?, t* a) Y" j% M - RS485_Receive_Data( datatemp, &len ) ;8 D: }! `7 _4 p, F6 C6 Q
- delay_ms( 10 ) ;
; V( n' c0 \2 x2 f0 p* y: | - }
: J- X& T; }% y& j% e, Q - }
复制代码
4 n* V6 Z) U4 ?3 Q; _( `6 V" j 文章出处: 滑小稽笔记 / K0 [( S0 P8 s3 F! I
|