本帖最后由 D5Power 于 2017-11-16 16:44 编辑 8 b/ Y3 b9 S c8 i/ r; H* G 向前翻页:STM32L4零基础学习笔记(四)串口通讯 8 L% t" X( I$ H7 f* K8 Q5 F 在前面的笔记中,小D研究了如何通过串口模块(CH340)进行数据的发送。在本篇笔记中,我们会尝试从电脑发送数据到开发板。并通知电脑已经收到数据。 一、发送数据的扩展——实现printf printf是一个小D非常喜欢的调试工具。而在前面的代码编写中,我发现这玩意写进去好像没有什么卵用。于是查了一下资料。原来在单片机中,printf是要自己通过串口发送来实现的(实际上输出的内容会出现在sscom软件中。)至于原理是怎么样的,现在不去深究。直接把代码贴进自己项目先用着。在此感谢各位前辈的无私奉献。 ; b" y& w6 q: m0 H( y首先,需要进行一个函数声明(可以直接写在main.c中) int fputc(int ch,FILE *f); 然后,进行函数实现: int fputc(int ch,FILE *f) { uint8_t temp[1]={ch}; HAL_UART_Transmit(&huart2,temp,1,2); } 7 k( t! h: ?* _& z9 X5 C" G7 }从代码中不难看出,其实就是通过HAL库的发送方法,将信息通过UART2发送出去。如果你的项目里使用的是其他串口,请注意修改。 现在,只需要正常的使用printf,在SSCOM软件中就可以看到输出了。可以开心的用printf调试啦。 二、一个小技巧 : C& K- H, C3 c7 p仔细观察STMCube帮我们生成的代码,小D发现,注释中标明了用户自己编写代码的区域。例如: /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ 3 b( Z0 |9 Q5 y) `$ A' [/* USER CODE END PV */ 或者 , q6 E) X/ x; B. _9 T, T- m/* USER CODE BEGIN 1 */ 6 z o- I# C7 i0 }- p+ B! j1 s. W! s/* USER CODE END 1 */ 因为我们经常需要在后期通过STMCubeMX修改项目配置,进而重新生成代码。此时,写在这些注释中间的代码,是不会被替换掉的。所以,养成好的习惯很重要。记得把自己的代码写在这些注释块中间,可以省掉不少重复敲代码的时间呢。 : \" M$ V6 Z& Q" v: F三、进入正题 4 s" I7 \4 t" i, ~在翻阅网上的资料后,小D决定使用来HAL_UART_Recive_IT来进行接收。于是冒冒失失就按照例子把代码敲进去了。结果调试发现,并没有什么卵用。传说中的HAL_UART_RxCpltCallback方法根本不会运行。那么,到底是为什么呢? HAL_UART_Recive_IT并不会影响主程序的运行,而是在收到规定长度的数据后,再通过HAL_UART_RxCpltCallback进行回调。那么,应该是中断没有被触发。经过多方查证,终于发现。中断模式必须要自己在STMCubeMX中配置,才会被启用。很多的新手引导贴都忽略了这个环节(估计是因为太基础了吧)。 打开STMCubeMX,通过Open Project打开自己的项目(啥?你不知道怎么打开,可以直接找到项目的保存目录,里面有一个.ioc的文件,双击,或打开项目时选择它都可以)。 - A2 g t! q( Y: ~' \: Q1 O1 a然后到配置界面(Configration)中,点击对应的串口,例如我的是USART2,然后找到中断设置(NVIC Setting),设置为允许中断(打勾即可)。如下图: 4 E9 ^- i2 ^+ i/ Y# K6 _设置好后,重新生成代码。如果忘记了如何重新生成代码,可以参考本篇笔记。 ( e1 T+ g% k! k首先,我们需要一个用来接收数据的缓冲区。因此,在全局变量中,我们声明了buffer,用来接收数据: uint8_t buffer[512] = ""; 然后,回到MDK中,打开main.c。在main函数中的while循环前,加入以下代码: if(HAL_UART_Receive_IT(&huart2,(uint8_t *)&buffer,1)!=HAL_OK) { printf("Recived error."); } # A0 ~/ x9 g7 s, U5 q! R, ]2 Z$ m然后,实现HAL_UART_RxCpltCallback方法: void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) { printf("Recived data."); HAL_UART_Receive_IT(&huart2,(uint8_t *)&buffer,1); } : S$ H- @0 w0 N+ ^当收到数据的时候,打印Recived data。 编译并上传入开发板,然后运行。每次在SSCOM中点击发送数据。就会收到开发板返回来的打印信息了。如下图: 说明开发板已经收到我们的数据了。并且还给出了响应。不过每次只收1个字节这种事情的确比较蛋疼。在实际的通讯中肯定不方便。原来在开发游戏的时候,我们一般都会采用自己的二进制协议来传输数据。那么,能不能把这些协议在单片机上实现呢?动手研究一下吧。 下一篇:STM32L4零基础学习笔记(六)串口通讯之踩到的坑' n0 B2 U, m3 z/ a7 f9 I/ r ----------------我是淫荡的分割线---------------- ) ~) X1 q; i; Z! r) r6 ] p7 N T 广告时间,编写中的笔记会在我个人的公众号进行,请各位高手斧正。 6 O* [7 c, c/ O4 b: T4 o |
可以直接调用vsnprintf,这样用户只需要实现一个串口发送str的函数即可,有时候log不仅仅是串口,还可以是lcd、sd卡等等,所以这个发送str的目的地可以随意设置,比重定向fputs、fgets方便多了!
收到!感谢指教
感谢版主大大打赏
顺便请教下,为什么开发板收到由SSCOM发过来的数据,跟我发出的不一样。哪怕只有1个字节
{
printf("Recived error.");
}
为什么要写在while(1)前呢
还有 如果不调用回调函数 可以吗
Recive_IT是会触发中断的。这样写是因为我希望在中断中去处理收到的数据(比如推进自己的缓冲区,等待解包处理。)。因此,在主循环开始前,设置收取1个字节的中断。然后在中断函数中,处理完这个字节,继续设置下一个中断。从而使中断连续运行。
具体后续的写法,可以参考第七篇笔记:简单数据协议