你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32L4零基础学习笔记(五)串口通讯之简单接收

[复制链接]
D5Power 发布时间:2017-11-6 08:36
本帖最后由 D5Power 于 2017-11-16 16:44 编辑
0 W' s; n; R  Y, @( u
0 K& \8 E/ Y% |, P- n2 k6 x向前翻页:STM32L4零基础学习笔记(四)串口通讯9 M  @. f5 [, g4 @, o. ]( b3 H
" D3 e9 Y+ ^! O
前面的笔记中,小D研究了如何通过串口模块(CH340)进行数据的发送。在本篇笔记中,我们会尝试从电脑发送数据到开发板。并通知电脑已经收到数据。
, w8 e# R4 W! z! ]- y2 J( p
3 v" r8 d8 C9 i/ g3 ~( w# a6 ^4 H
一、发送数据的扩展——实现printf

+ p6 v# i+ `& b7 X9 N% v/ k
printf是一个小D非常喜欢的调试工具。而在前面的代码编写中,我发现这玩意写进去好像没有什么卵用。于是查了一下资料。原来在单片机中,printf是要自己通过串口发送来实现的(实际上输出的内容会出现在sscom软件中。)至于原理是怎么样的,现在不去深究。直接把代码贴进自己项目先用着。在此感谢各位前辈的无私奉献。
9 X" h5 [& L1 k7 H
首先,需要进行一个函数声明(可以直接写在main.c中)
& @' s, M- z! r% R$ H9 C& k
int fputc(int ch,FILE *f);

9 B, S' P& l, K2 M1 K7 `5 m3 j
然后,进行函数实现:

  x# E2 {% ^" S6 M
int fputc(int ch,FILE *f)
{
uint8_t temp[1]={ch};
HAL_UART_Transmit(&huart2,temp,1,2);
}
* C& s- ?# X* k/ ^0 q# d; d- A! r
从代码中不难看出,其实就是通过HAL库的发送方法,将信息通过UART2发送出去。如果你的项目里使用的是其他串口,请注意修改。

$ ?' Y- Y# s2 T# L3 Q* v" P3 Q3 l
现在,只需要正常的使用printf,在SSCOM软件中就可以看到输出了。可以开心的用printf调试啦。
) y% ~! v$ |" f2 y
二、一个小技巧
. ~2 k$ B( h" F
仔细观察STMCube帮我们生成的代码,小D发现,注释中标明了用户自己编写代码的区域。例如:
5 g/ n* k$ y/ k2 }7 u0 d( |
/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
/ ^5 f4 e7 c. m. M8 F( K
/* USER CODE END PV */
) o7 N% z5 L6 S# x
或者

2 F4 E4 n2 U% P7 ~# r: ^
/* USER CODE BEGIN 1 */
/ E$ b" b1 c& }' \+ Y- k
/* USER CODE END 1 */
( t. y  {3 d9 q' T
因为我们经常需要在后期通过STMCubeMX修改项目配置,进而重新生成代码。此时,写在这些注释中间的代码,是不会被替换掉的。所以,养成好的习惯很重要。记得把自己的代码写在这些注释块中间,可以省掉不少重复敲代码的时间呢。

# k* a, ]2 P9 ], D" |+ j& P
三、进入正题

, K! R5 y8 M& U
在翻阅网上的资料后,小D决定使用来HAL_UART_Recive_IT来进行接收。于是冒冒失失就按照例子把代码敲进去了。结果调试发现,并没有什么卵用。传说中的HAL_UART_RxCpltCallback方法根本不会运行。那么,到底是为什么呢?

$ ?( V" S' Q: C  h/ C
HAL_UART_Recive_IT并不会影响主程序的运行,而是在收到规定长度的数据后,再通过HAL_UART_RxCpltCallback进行回调。那么,应该是中断没有被触发。经过多方查证,终于发现。中断模式必须要自己在STMCubeMX中配置,才会被启用。很多的新手引导贴都忽略了这个环节(估计是因为太基础了吧)。

2 G" w" a( I$ z) {  e2 j2 j
打开STMCubeMX,通过Open Project打开自己的项目(啥?你不知道怎么打开,可以直接找到项目的保存目录,里面有一个.ioc的文件,双击,或打开项目时选择它都可以)。

  F1 K* G. y. Z
然后到配置界面(Configration)中,点击对应的串口,例如我的是USART2,然后找到中断设置(NVIC Setting),设置为允许中断(打勾即可)。如下图:

$ p% x) O: w+ q6 u2 y# j
1.png
9 Q4 F, u* _$ v' G4 P
设置好后,重新生成代码。如果忘记了如何重新生成代码,可以参考本篇笔记
# }# e9 |: v5 h1 ^! X) k4 _# `
首先,我们需要一个用来接收数据的缓冲区。因此,在全局变量中,我们声明了buffer,用来接收数据:
2 O$ x* |& }+ s% C# Q( H9 j5 t
uint8_t buffer[512] = "";

! }9 W+ L8 P2 e4 C
然后,回到MDK中,打开main.c。在main函数中的while循环前,加入以下代码:
7 p" B. H+ F' n9 m1 k
if(HAL_UART_Receive_IT(&huart2,(uint8_t *)&buffer,1)!=HAL_OK)
  {
    printf("Recived error.");
  }
% u. B* o0 h: G- T6 [2 w" r
然后,实现HAL_UART_RxCpltCallback方法:

/ c1 B5 N) |7 a  n2 T5 Q0 a. Z
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
    printf("Recived data.");
    HAL_UART_Receive_IT(&huart2,(uint8_t *)&buffer,1);
}
/ o9 f5 m# U( d: Z
当收到数据的时候,打印Recived data。

# Z4 H  }4 E  S7 r" [; ?
编译并上传入开发板,然后运行。每次在SSCOM中点击发送数据。就会收到开发板返回来的打印信息了。如下图:

; Q$ z  H, v; \* K
2.png
6 f3 _0 k" f3 P, @, H
说明开发板已经收到我们的数据了。并且还给出了响应。不过每次只收1个字节这种事情的确比较蛋疼。在实际的通讯中肯定不方便。原来在开发游戏的时候,我们一般都会采用自己的二进制协议来传输数据。那么,能不能把这些协议在单片机上实现呢?动手研究一下吧。
, M5 f8 P1 W! r* b9 q
下一篇:STM32L4零基础学习笔记(六)串口通讯之踩到的坑; @2 S$ Q3 V; @8 Q) t( |0 F) h" I
! {" g# M! V/ g# L
----------------我是淫荡的分割线----------------

" `! M. `7 M  ^3 C( o" L0 q
  广告时间,编写中的笔记会在我个人的公众号进行,请各位高手斧正。
/ K7 X  m5 x- {  T- _( E8 c
qrcode_for_gh_bb8c73d98b29_344.jpg

& j0 X" @+ ]* Q( x3 o

评分

参与人数 1 ST金币 +6 收起 理由
MrJiu + 6 支持基础知识。。。

查看全部评分

收藏 评论7 发布时间:2017-11-6 08:36

举报

7个回答
D5Power 回答时间:2017-11-6 08:43:49
汗,是刚好赶上管理员上班么,秒审啊@creep
Inc_brza 回答时间:2017-11-6 09:02:30
重定向已经太low了,0 ?5 w; Q. G& B4 B4 y
可以直接调用vsnprintf,这样用户只需要实现一个串口发送str的函数即可,有时候log不仅仅是串口,还可以是lcd、sd卡等等,所以这个发送str的目的地可以随意设置,比重定向fputs、fgets方便多了!
D5Power 回答时间:2017-11-6 09:07:38
Inc_brza 发表于 2017-11-6 09:02
$ N' O. v2 p/ W* k4 B; a$ V重定向已经太low了,
4 Q; q  y* ~2 m可以直接调用vsnprintf,这样用户只需要实现一个串口发送str的函数即可,有时候log不 ...

$ h% ^7 x6 Q  i1 N& h收到!感谢指教
MrJiu 回答时间:2017-11-7 11:31:08
顶。。。
D5Power 回答时间:2017-11-7 15:28:00
本帖最后由 D5Power 于 2017-11-7 15:29 编辑 ! i+ T" Y4 Q, x# c" B
MrJiu 发表于 2017-11-7 11:31" n# u% m1 K( X' Q8 S
顶。。。
$ o, F. l2 a# X% o: g
感谢版主大大打赏
9 r; W0 _5 g  n5 N2 f顺便请教下,为什么开发板收到由SSCOM发过来的数据,跟我发出的不一样。哪怕只有1个字节
april1818 回答时间:2017-11-17 00:14:30
请问 if(HAL_UART_Receive_IT(&huart2,(uint8_t *)&buffer,1)!=HAL_OK)
  _) R1 ^6 ]. j. G$ \6 c  {" `; I  Z8 G3 K% i7 w
    printf("Recived error.");2 u/ y. s( R; J9 E
  }
7 X) v: @( |1 s' y$ q5 y为什么要写在while(1)前呢
- z& c9 M% e: w7 n' D还有 如果不调用回调函数 可以吗
D5Power 回答时间:2017-11-17 08:31:39
april1818 发表于 2017-11-17 00:14
9 c* R  c$ M8 e. v3 m9 u请问 if(HAL_UART_Receive_IT(&huart2,(uint8_t *)&buffer,1)!=HAL_OK). f5 F! K" C! H* p. R
  {
3 `$ [& |. g4 ~    printf("Recived error."); ...

  {& Y8 \' J- i- i3 ?Recive_IT是会触发中断的。这样写是因为我希望在中断中去处理收到的数据(比如推进自己的缓冲区,等待解包处理。)。因此,在主循环开始前,设置收取1个字节的中断。然后在中断函数中,处理完这个字节,继续设置下一个中断。从而使中断连续运行。7 P- A; {3 }! C  n9 O1 i
2 N* `8 I5 h/ Y/ r, G5 H
具体后续的写法,可以参考第七篇笔记:简单数据协议
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版