-
stm32串口
2015-08-17 14:14:25STM32的串口是相当丰富的,功能也很强劲。最多可提供5路串口(MiniSTM32使用的是STM32F103RBT6,具有3个串口),有分数波特率发生器、支持单线光通信和半双工单线通讯、支持LIN、智能卡协议和IrDASIR ENDEC规范(仅...STM32的串口是相当丰富的,功能也很强劲。最多可提供5路串口(MiniSTM32使用的是STM32F103RBT6,具有3个串口),有分数波特率发生器、支持单线光通信和半双工单线通讯、支持LIN、智能卡协议和IrDASIR ENDEC规范(仅串口3支持)、具有DMA等。
串口最基本的设置,就是波特率的设置。STM32的串口使用起来还是蛮简单的,只要你开启了串口时钟,并设置相应IO口的模式,然后配置一下波特率,数据位长度,奇偶校验位等信息,就可以使用了。下面,我们就简单介绍下这几个与串口基本配置直接相关的寄存器。
1,串口时钟使能。串口作为STM32的一个外设,其时钟由外设时钟使能寄存器控制,这里我们使用的串口1是在APB2ENR寄存器的第14位。APB2ENR寄存器在之前已经介绍过了,这里不再介绍。只是说明一点,就是除了串口1的时钟使能在APB2ENR寄存器,其他串口的时钟使能位都在APB1ENR。
2,串口复位。当外设出现异常的时候可以通过复位寄存器里面的对应位设置,实现该外设的复位,然后重新配置这个外设达到让其重新工作的目的。一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。串口1的复位是通过配置APB2RSTR寄存器的第14位来实现的。APB2RSTR寄存器的各位描述如下:
图3.3.1.1寄存器APB2RSTR各位描述
从上图可知串口1的复位设置位在APB2RSTR的第14位。通过向该位写1复位串口1,写0结束复位。其他串口的复位位在APB1RSTR里面。
3,串口波特率设置。每个串口都有一个自己独立的波特率寄存器USART_BRR,通过设置该寄存器达到配置不同波特率的目的。该寄存器的各位描述如下:
图3.3.1.2寄存器USART_BRR各位描述
前面提到STM32的分数波特率概念,其实就是在这个寄存器里面体现的。最低4位用来存放小数部分DIV_Fraction,[15:4]这12位用来存放整数部分DIV_Mantissa。高16位未使用。这里波特率的计算通过如下公式计算:
这里的fpclkx(x=1、2)是给外设的时钟(PCLK1用于串口2、3、4、5,PCLK2用于串口1),USARTDIV是一个无符号的定点数,它的值可以有串口的BRR寄存器值得到。而我们更关心的是如何从USARTDIV的值得到USART_BRR的值,因为一般我们知道的是波特率,和PCLKx的时钟,要求的就是USART_BRR的值。
下面我们来介绍如何通过USARTDIV得到串口USART_BRR寄存器的值,假设我们的串口1要设置为9600的波特率,而PCLK2的时钟为72M。这样,我们根据上面的公式有:USARTDIV=72000000/9600*16=468.75
那么得到:DIV_Fraction=16*0.75=12=0X0C; DIV_Mantissa= 468=0X1D4;
这样,我们就得到了USART1->BRR的值为0X1D4C。只要设置串口1的BRR寄存器值为0X1D4C就可以得到9600的波特率。
4,串口控制。STM32的每个串口都有3个控制寄存器USART_CR1~3,串口的很多配置都是通过这3个寄存器来设置的。这里我们只要用到USART_CR1就可以实现我们的功能了。
BIT 13: 串口功能;
BIT 12: MODE,字长。0: 1个开始位,8个数据位,1位停止位(默认);1: 1个开始位,9位数据位,1位停止位(默认);
*注意:停止位的长度可在USART_CR2寄存器中设置。
BIT 11: WAKE 唤醒功能
BIT 10: 校检使能位,当激活奇偶校验功能时,置位该位将自动往要传输数据的高位字节处插入就校验位。
BIT 09: Parity Selection,0:偶校验;1:奇校验。
BIT 08: PE Interrupt Enable
BIT 07: 发送缓冲区空中断使能位BIT 06: 发送完成中断使能位
BIT 05: 接收缓冲区非空中断使能位
BIT 04: Idle Interrupt Enable
BIT 03: Transfer Enable
BIT 02: Receive Enable
BIT 01: Receiver Wakeup
BIT 00: Send Break
5,数据发送与接收。STM32的发送与接收是通过数据寄存器USART_DR来实现的,这是一个双寄存器,包含了TDR和RDR。当向该寄存器写数据的时候,串口就会自动发送,当收到收据的时候,也是存在该寄存器内。该寄存器的各位描述如下:
图3.3.1.3寄存器USART_DR各位描述
可以看出,虽然是一个32位寄存器,但是只用了低9位(DR[8:0]),其他都是保留。
DR[8:0]为串口数据,包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR),一个给接收用(RDR),该寄存器兼具读和写的功能。TDR寄存器提供了内部总线和输出移位寄存器之间的并行接口。RDR寄存器提供了输入移位寄存器和内部总线之间的并行接口。
当使能校验位(USART_CR1种PCE位被置位)进行发送时,写到MSB的值(根据数据的长度不同,MSB是第7位或者第8位)会被后来的校验位该取代。
当使能校验位进行接收时,读到的MSB位是接收到的校验位。
6,串口状态。串口的状态可以通过状态寄存器USART_SR读取。USART_SR的各位描述如下: -
STM32串口发送数据和接收数据方式总结
2018-05-13 20:34:22之前写了篇关于ESP8266使用AT指令进行互相通讯的实验,在写STM32串口接发数据的程序中,觉得有必要将之前学的有关于串口方面的使用经历加以总结。 串口发送数据: 1. 串口发送数据最直接的方式就是标准调用...之前写了篇关于ESP8266使用AT指令进行互相通讯的实验,在写STM32串口接发数据的程序中,觉得有必要将之前学的有关于串口方面的使用经历加以总结。
串口发送数据:
1. 串口发送数据最直接的方式就是标准调用库函数 。 void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
第一个参数是发送的串口号,第二个参数是要发送的数据了。但是用过的朋友应该觉得不好用,一次只能发送单个字符,所以我们有必要根据这个函数加以扩展。void Send_data(u8 *s) { while(*s!='\0') { while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET); USART_SendData(USART1,*s); s++; } }
以上程序的形参就是我们调用该函数时要发送的字符串,这里通过循环调用USART_SendData来一 一发送我们的字符串。
while(USART_GetFlagStatus(USART1,USART_FLAG_TC )==RESET);
这句话有必要加,他是用于检查串口是否发送完成的标志,如果不加这句话会发生数据丢失的情况。这个函数只能用于串口1发送。有些时候根据需要,要用到多个串口发送那么就还需要改进这个程序。如下:
void Send_data(USART_TypeDef * USARTx,u8 *s) { while(*s!='\0') { while(USART_GetFlagStatus(USARTx,USART_FLAG_TC )==RESET); USART_SendData(USARTx,*s); s++; } }
这样就可实现任意的串口发送。但有一点,我在使用实时操作系统的时候(如UCOS,Freertos等),需考虑函数重入的问题。当然也可以简单的实现把该函数复制一下,然后修改串口号也可以避免该问题。然而这个函数不能像printf那样传递多个参数,所以还可以在改进,最终程序如下
void USART_printf ( USART_TypeDef * USARTx, char * Data, ... ) { const char *s; int d; char buf[16]; va_list ap; va_start(ap, Data); while ( * Data != 0 ) // 判断是否到达字符串结束符 { if ( * Data == 0x5c ) //'\' { switch ( *++Data ) { case 'r': //回车符 USART_SendData(USARTx, 0x0d); Data ++; break; case 'n': //换行符 USART_SendData(USARTx, 0x0a); Data ++; break; default: Data ++; break; } } else if ( * Data == '%') { // switch ( *++Data ) { case 's': //字符串 s = va_arg(ap, const char *); for ( ; *s; s++) { USART_SendData(USARTx,*s); while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET ); } Data++; break; case 'd': //十进制 d = va_arg(ap, int); itoa(d, buf, 10); for (s = buf; *s; s++) { USART_SendData(USARTx,*s); while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET ); } Data++; break; default: Data++; break; } } else USART_SendData(USARTx, *Data++); while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET ); } }
该函数就可以像printf使用可变参数,方便很多。通过观察函数但这个函数只支持了%d,%s的参数,想要支持更多,可以仿照printf的函数写法加以补充。
2. 直接使用printf函数。 很多朋友都知道想要STM32要直接使用printf不行的。需要加上以下的重映射函数如果不想添加以上代码,也可以勾选以下的Use MicroLI选项来支持printf函数使用。
串口接收数据:
串口接收最后应有一定的协议,如发送一帧数据应该有头标志或尾标志,也可两个标志都有。这样在处理数据时既能能保证数据的正确接收,也有利于接收完后我们处理数据。串口的配置在这里就不在赘述,这里我以串口2接收中断服务程序函数且接收的数据包含头尾标识为例。
#define Max_BUFF_Len 18 unsigned char Uart2_Buffer[Max_BUFF_Len]; unsigned int Uart2_Rx=0;
void USART2_IRQHandler() { if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET) //中断产生 { USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除中断标志 Uart2_Buffer[Uart2_Rx] = USART_ReceiveData(USART2); //接收串口1数据到buff缓冲区 Uart2_Rx++; if(Uart2_Buffer[Uart2_Rx-1] == 0x0a || Uart2_Rx == Max_BUFF_Len) //如果接收到尾标识是换行符(或者等于最大接受数就清空重新接收) { if(Uart2_Buffer[0] == '+') //检测到头标识是我们需要的 { printf("%s\r\n",Uart2_Buffer); //这里我做打印数据处理 Uart2_Rx=0; } else { Uart2_Rx=0; //不是我们需要的数据或者达到最大接收数则开始重新接收 } } } }
数据的头标识为“\n”既换行符,尾标识为“+”。该函数将串口接收的数据存放在USART_Buffer数组中,然后先判断当前字符是不是尾标识,如果是说明接收完毕,然后再来判断头标识是不是“+”号,如果还是那么就是我们想要的数据,接下来就可以进行相应数据的处理了。但如果不是那么就让Usart2_Rx=0重新接收数据。这样做的有以下好处:1.可以接受不定长度的数据,最大接收长度可以通过Max_BUFF_Len来更改
2.可以接受指定的数据
3.防止接收的数据使数组越界
这里我的把接受正确数据直接打印出来,也可以通过设置标识位,然后在主函数里面轮询再操作。以上的接收形式,是中断一次就接收一个字符,这在UCOS等实时内核系统中频繁的中断,非常消耗CPU资源,在有些时候我们需要接收大量数据时且波特率很高的情况下,长时间中断会带来一些额外的问题。所以以DMA形式配合串口的IDLE(空闲中断)来接受数据将会大大的提高CPU的利用率,减少系统资源的消耗。首先还是先看代码。
#define DMA_USART1_RECEIVE_LEN 18
void USART1_IRQHandler(void) { u32 temp = 0; uint16_t i = 0; if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET) { USART1->SR; USART1->DR; //这里我们通过先读SR(状态寄存器)和DR(数据寄存器)来清USART_IT_IDLE标志 DMA_Cmd(DMA1_Channel5,DISABLE); temp = DMA_USART1_RECEIVE_LEN - DMA_GetCurrDataCounter(DMA1_Channel5); //接收的字符串长度=设置的接收长度-剩余DMA缓存大小 for (i = 0;i < temp;i++) { Uart2_Buffer[i] = USART1_RECEIVE_DMABuffer[i]; } //设置传输数据长度 DMA_SetCurrDataCounter(DMA1_Channel5,DMA_USART1_RECEIVE_LEN); //打开DMA DMA_Cmd(DMA1_Channel5,ENABLE); } }
之前的串口中断是一个一个字符的接收,现在改为串口空闲中断,就是一帧数据过来才中断进入一次。而且接收的数据时候是DMA来搬运到我们指定的缓冲区(也就是程序中的USART1_RECEIVE_DMABuffer数组),是不占用CPU时间资源的。具体什么是IDLE中断和DMA需要朋友们先行了解。
参考链接:
https://blog.csdn.net/jdh99/article/details/8444474
https://blog.csdn.net/phker/article/details/51925668
最后在讲下DMA的发送
#define DMA_USART1_SEND_LEN 64
void DMA_SEND_EN(void) { DMA_Cmd(DMA1_Channel4, DISABLE); DMA_SetCurrDataCounter(DMA1_Channel4,DMA_USART1_SEND_LEN); DMA_Cmd(DMA1_Channel4, ENABLE); }
这里需要注意下DMA_Cmd(DMA1_Channel4,DISABLE)函数需要在设置传输大小之前调用一下,否则不会重新启动DMA发送。
有了以上的接收方式,对一般的串口数据处理是没有问题的了。下面再讲一下,在ucosiii中我使用信号量+消息队列+储存管理的形式来处理我们的串口数据。先来说一下这种方式对比其他方式的一些优缺点。一般对串口的处理形式是"生产者"和"消费者"的模式,即本次接收的数据要马上处理,否则当数据大量涌进的时候,就来不及"消费"掉生产者(串口接收中断)的数据,那么就会丢失本次的数据处理。所以使用队列就能够很方便的解决这个问题。
在下面的程序中,对数据的处理是先接受,在处理,如果在处理的过程中,有串口中断接受数据,那么就把它依次放在队列中,队列的特征是先进先出,在串口中就是先处理先接受的数据,所以根据生产和消费的速度,定义不同大小的消息队列缓冲区就可以了。缺点就是太占用系统资源,一般51单片机是没可能了。下面是从我做的项目中截取过来的程序
OS_MSG_SIZE Usart1_Rx_cnt; //字节大小计数值 unsigned char Usart1_data; //每次中断接收的数据 unsigned char* Usart1_Rx_Ptr; //储存管理分配内存的首地址的指针 unsigned char* Usart1_Rx_Ptr1; //储存首地址的指针
void USART1_IRQHandler() { OS_ERR err; OSIntEnter(); if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE) != RESET) //中断产生 { USART_ClearFlag(USART1, USART_FLAG_RXNE); //清除中断标志 Usart1_data = USART_ReceiveData(USART1); //接收串口1数据到buff缓冲区 if(Usart1_data =='+') //接收到数据头标识 { // OSSemPend((OS_SEM* )&SEM_IAR_UART, //这里请求信号量是为了保证分配的存储区,但一般来说不允许 // (OS_TICK )0, //在终端服务函数中调用信号量请求但因为 // (OS_OPT )OS_OPT_PEND_NON_BLOCKING,//我OPT参数设置为非阻塞,所以可以这么写 // (CPU_TS* )0, // (OS_ERR* )&err); // if(err==OS_ERR_PEND_WOULD_BLOCK) //检测到当前信号量不可用 // { // printf("error"); // } Usart1_Rx_Ptr=(unsigned char*) OSMemGet((OS_MEM*)&UART1_MemPool,&err);//分配存储区 Usart1_Rx_Ptr1=Usart1_Rx_Ptr; //储存存储区的首地址 } if(Usart1_data == 0x0a ) //接收到尾标志 { *Usart1_Rx_Ptr++=Usart1_data; Usart1_Rx_cnt++; //字节大小增加 OSTaskQPost((OS_TCB * )&Task1_TaskTCB, (void * )Usart1_Rx_Ptr1, //发送存储区首地址到消息队列 (OS_MSG_SIZE )Usart1_Rx_cnt, (OS_OPT )OS_OPT_POST_FIFO, //先进先出,也可设置为后进先出,再有地方很有用 (OS_ERR * )&err); Usart1_Rx_Ptr=NULL; //将指针指向为空,防止修改 Usart1_Rx_cnt=0; //字节大小计数清零 } else { *Usart1_Rx_Ptr=Usart1_data; //储存接收到的数据 Usart1_Rx_Ptr++; Usart1_Rx_cnt++; } } OSIntExit(); }
上面被注释掉的代码为我是为了防止当分区中没有空闲的存储块时加入信号量,打印出报警信息。当然我们也可以将存储块直接设置大一点,但是还是无法避免当没有可有存储块时会程序会崩溃现象。希望懂的朋友能告知下~。
下面是串口数据处理任务,这里删去了其他代码,只把他打印出来了而已。
void task1_task(void *p_arg) { OS_ERR err; OS_MSG_SIZE Usart1_Data_size; u8 *p; while(1) { p=(u8*)OSTaskQPend((OS_TICK )0, //请求消息队列,获得储存区首地址 (OS_OPT )OS_OPT_PEND_BLOCKING, (OS_MSG_SIZE* )&Usart1_Data_size, (CPU_TS* )0, (OS_ERR* )&err); printf("%s\r\n",p); //打印数据 delay_ms(100); OSMemPut((OS_MEM* )&UART1_MemPool, //释放储存区 (void* )p, (OS_ERR* )&err); OSSemPost((OS_SEM* )&SEM_IAR_UART, //释放信号量 (OS_OPT )OS_OPT_POST_NO_SCHED, (OS_ERR* )&err); OSTimeDlyHMSM(0,0,1,500,OS_OPT_TIME_PERIODIC,&err); } }
-
STM32踩坑:STM32串口发送乱码问题
2020-10-16 09:36:05STM32串口发送乱码问题 小编是一个嵌入式初学者,才学没多久,将近两个月的样子,在学习过程中遇到了一些问题,在这里给大家分享一下解决方案。 今天要分享的问题是 STM32 串口发送字符串,但是在调试助手上面接收到...STM32串口发送乱码问题
小编是一个嵌入式初学者,才学没多久,将近两个月的样子,在学习过程中遇到了一些问题,在这里给大家分享一下解决方案。
今天要分享的问题是 STM32 串口发送字符串,但是在调试助手上面接收到的字符却是一串乱码,看着让人头疼。
这是乱码的图片然后问了公司办公室的大佬,也在网上查了一下资料,总结了一下,原因大致有两点:
1) 开发板上外部时钟的晶振与代码中的外部时钟的晶振不一致(这是我写的串口实验发生乱码的原因)
2) 串口调试助手接收数据的波特率与串口初始化时的波特率不一致(这种乱码情况我没有遇见过)
如果是第一种情况,那么找到 stm32Fxxx.h (F1 系列的是 stm32F1xx.h,F3 系列的是 stm32F3xx.h,F4 系列的是 stm32F4xx.h,F7 系列的是 stm32F7xx.h,没用过 F3 系列的,不过文件应该是对应的)文件,找到以下相对应的代码进行修改即可。
//以下代码是对 HSE 外部高速时钟的晶振的一个设置 //修改前 #define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
//修改后 #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
这里我是将参数 25000000 改成了 8000000,具体的还是要看开发板上晶振模块的数值。
如果是第二种情况,那么就需要检查串口调试助手接收数据的波特率与串口初始化时的波特率(一般在串口初始化函数中,如果使用的自带的函数初始化,那么需要找到对应的文件进行修改)是否一致了,下面是我自己的检查结果截图,仅供参考。
下面是修改成功后,调试助手收到的结果截图。
以上均为小编自己的总结,若存在侵权,请联系小编。 -
stm32串口isp
2018-01-18 11:17:28原文地址:http://nicekwell.net/blog/20180118/stm32chuan-kou-isp.html这里介绍stm32串口isp实现方法,包含st官方协议整理和实现...概述stm32串口ISP程序,基于c语言。在ubuntu和mac下测试都ok,ubuntu下需要修改/de原文地址:http://nicekwell.net/blog/20180118/stm32chuan-kou-isp.html
这里介绍stm32串口isp实现方法,包含st官方协议整理和实现代码。
已提交到github https://github.com/nicekwell/stm32ISP。
概述
stm32串口ISP程序,基于c语言。
在ubuntu和mac下测试都ok,ubuntu下需要修改/dev/ttyUSB0权限,mac下不需要修改。
本程序在stm32f103c8t6上ok,根据官方文档,其他型号单片机下载协议相同,但没有测试过。使用方法:
stm32isp /dev/ttyUSB0 stm32_test.bin
mac下的usb串口节点是 /dev/tty.usbserial注:
- 波特率固定为57600不允许修改。实际上测试了各种波特率,只有57600和38400可以稳定下载(程序写的还不太稳定吧),所以波特率固定为了57600。
- 下载的是bin文件,不是hex文件。bin文件是纯粹的编码,hex文件包含了地址信息。keil默认不生成bin文件,生成bin文件的方法可网上查找。
广告
老婆做毕业设计,给我下了死命令,一定要找300个程序员研究一下,请各位同行做个调查问卷,可扫描下面二维码或者直接点击此链接:https://www.wjx.cn/jq/17710478.aspx,多谢!
移除
ad.jpg 下载协议
stm32官方文档已提交到本工程 documents 目录下。https://github.com/nicekwell/stm32ISP/raw/master/documents/stm32isp%20application%20note.pdf
1、硬件
首先要让stm32进入bootloader启动:
引脚电平BOOT0高电平BOOT1低电平
这样启动后就会从system分区启动,开始接收串口数据。
连接串口1:
引脚功能PA9TXD,连接host RXDPA10RXD,连接host TXD
2、sync
以下数据指的是响应host或device端发送的数据。
hostdevicenote0x7f-发送0x7f,单片机收到后会自动匹配波特率。-0x79(ACK)/0x1F(NACK)device返回ACK或NACK,表示对host的反应。
适配波特率这一步是无条件执行的,执行完这一步之后就可以接收各种指令。
下面就介绍各个指令的功能和数据协议。3、get command
在上面已经适配波特率情况下可以执行此指令。
【指令码】0x00
【功能】获取stm32里bootloader版本号,以及所有支持的指令代码。
【数据协议】hostdevicenote0x00 + 0xff- -0x79(ACK)/0x1F(NACK) -N1字节,表示下面要接收到的字节数。bootloaderversion字节数 + 所有指令字节数 = N+1-bootloader version1字节,如0x21代表2.1版本-所有支持的指令多个字节,每个字节数据都表示一个支持的指令-0x79(ACK)/0x1F(NACK)指令执行结束后会返回0x79
4、get version & read protection
【指令码】0x01
【功能】获取stm32里bootloader版本号,读取保护状态。
【数据协议】hostdevicenote0x01+0xfe- -0x79(ACK)/0x1F(NACK) -bootloader version -2个字节这两个字节和保护状态有关-0x79(ACK)/0x1F(NACK)
5、get ID command
【指令码】0x02
【功能】获取stm32 PID(product ID,不是芯片唯一识别码)。
【数据协议】hostdevicenote0x02+0xfd- -0x79(ACK)/0x1F(NACK) -N1字节,表示下面 PID字节数 - 1-PID多字节(上一个字节已指明字节数),先传高位后传低位。我这次用的stm32f103c8t6是2字节。-0x79(ACK)/0x1F(NACK)
6、Erase Memory command
【指令码】0x43
【功能】擦除flash,可以全擦或擦除一部分,这里只介绍全擦。
【数据协议】hostdevicenote0x43+0xbc- -0x79(ACK)/0x1F(NACK) 0xff+0x00-这是全擦指令-0x79(ACK)/0x1F(NACK)
7、Write Memory command
【指令码】0x31
【功能】
写存储器,可以写任意的RAM、flash,我们写程序就用这个。
【数据协议】hostdevicenote0x31+0xCE- -0x79(ACK)/0x1F(NACK) addr-4字节,下载地址。用户flash起始地址是0x08000000。
先发高位,后发低位
addr checksum-1字节,地址的checksum,就是上面4字节数据的异或。-0x79(ACK)/0x1F(NACK) count-1字节,表示后面将要传输的字节数,范围(0, 255]。
字节数 = 这个值+1
,也就是说最大传输256字节。data-多字节,字节数 = count + 1,最大256字节。
这里下载进去的是bin文件,不是hex。。
checksum-1字节,上面的data数据,以及数据个数count的checksum。注意这里的checksum包含
数据和个数
。-0x79(ACK)/0x1F(NACK)
注:
- 对于写flash,用户flash的起始地址是0x08000000。
- 对于写flash,这里最多一次写256字节,写一个bin文件需要多次使用此协议写入。
8、Read Memory command
【指令码】0x11
【功能】
读取stm32内存,可以读取stm32任意地址的RAM、flash等数据。
我们常在下载完成后把flash内容读取出来验证。
【数据协议】hostdevicenote0x11+0xEE0x79(ACK)/0x1F(NACK) addr-4字节,下载地址。用户flash起始地址是0x08000000。
先发高位,后发低位
addr checksum-1字节,地址的checksum,就是上面4字节数据的异或。-0x79(ACK)/0x1F(NACK) count-1字节,将要读取的数据个数,0~255。count+1就是将要读取的字节数,最多读取256字节。checksum-1字节,count的按位取反。-0x79(ACK)/0x1F(NACK) -datacount+1个字节,这就是要读取的数据。
注:
- 对于读取flash,用户flash的起始地址是0x08000000。
- 一次最多读取256字节,要读取大段内容就重复执行这个读取操作。
9、Go command
略。
代码说明
根据上面的下载协议,封装成了模块,这里介绍本程序结构和模块的使用,以便移植到其他地方。
程序结构
wiringSerial.c wiringSerial.h
串口驱动,在树莓派wiringPi基础上修改,增加了数据块读写代码,增加了更多设置项。
这部分驱动在mac、桌面ubuntu、树莓派上都可以使用。stm32isp.c stm32isp.h
下载逻辑代码,基于串口驱动,串口的打开、关闭操作也归于这部分控制。
以上两个部分,serial完全归于stm32isp,外部使用stm32isp时不需要再管串口了。main.c
程序交互的实现,调用上面stm32isp接口实现下载。下面着重介绍的是stm32isp部分的接口函数。
stm32isp接口
stm32isp使用前提是串口工作正常。
stm32isp_init
int stm32isp_init(const char *device, const int baud, const int databits, const int stopbits, const char parity, const int timeout);
使用前需要先调用此函数,主要是完成串口初始化(串口的打开和关闭也交给stm32isp模块管理)。
例:
stm32isp_init("/dev/ttyUSB0", 57600, 8, 1, 'N', 30);
注:此驱动测试只有57600和38400两个波特率可以正常下载。
stm32isp_close
void stm32isp_close(); //成功返回1,失败返回0
下载结束后调用此函数,主要是完成串口关闭(串口的打开和关闭也交给stm32isp模块管理)。
stm32isp_sync
int stm32isp_sync();
同步波特率,成功返回1,失败返回0。 打开串口后第一步就需要sync,和单片机同步波特率。
stm32isp_get_command
int stm32isp_get_command()
获取ID和command列表,信息保存在驱动内部结构体,不输出,但会进行打印信息。成功返回1,失败返回0。
这一步不是下载必须执行的。
stm32isp_get_ID_command
int stm32isp_get_ID_command();
获取PID,信息保存在驱动内部结构体,不输出,但会进行打印。成功返回1,失败返回0。
这一步不是下载必须执行的。
stm32isp_erase_all
int stm32isp_erase_all();
全擦flash,成功返回1,失败返回0。
下载之前先擦除flash。
stm32isp_write_bin
int stm32isp_write_bin(char *p);
传入bin文件路径,写入bin文件到flash,成功返回1,失败返回0。
注意写入的是bin文件,不是hex文件。
bin文件路径可能由main函数的argv参数传入。
stm32isp_verify
int stm32isp_verify(char *p);
传入bin文件路径,根据bin文件大小读取flash相应大小内容,并把两个比较,验证成功返回1,失败返回0。
这一步可选,为了保险可下载后验证一下。
-
基于STM32串口通信的ESP8266WiFi模块使用
2019-04-01 15:28:32掌握esp8266的使用可以实现真正的万物物联。esp8266wifi通信对于MCU而言归结到底还是串口或spi通信。因此,掌握RS232通信协议、SPI通信协议以及esp8266的配置就可以基本搞定WiFi模块的使用。...[3] STM32串口接收... -
STM32串口下载程序
2020-02-05 09:33:08STM32 串口下载程序 引言: 如果我们用下载器下载程序很快,很方便,但是需要购买下载器,很破费。为此我们用串口 下载程序,省去了购买下载器的麻烦。 下面介绍用串口下载程序的方法: 所需工具: 串口转 TTL ... -
openmv和stm32串口通信完成二维码识别
2021-03-21 22:28:25openmv和stm32串口通信完成二维码识别 文章目录前言一、所用的硬件:二、openmv端2.stm32端总结 前言 注:我只是个大一的小白,本文只完成基本功能,希望能帮助有困惑的人(我也是刚刚走出谜团,大佬勿喷。) 工训... -
STM32串口接收数据
2018-07-15 13:33:28参考:STM32串口接收粉尘传感器数据 -
STM32串口下载
2017-04-19 22:52:231、参考资料 《STM32F1开发指南-库函数版本》-3.4.2 STM32串口程序下载 2、PA9(T) PA10(R) 串口下载引脚 3、USB/串口转换电路 CH340 FLYMCU 4、下载硬件连接:PA9 和 PA10跳线帽 B0和B1和GND跳线帽 ... -
STM32 串口程序下载
2019-01-06 14:55:25使用USB线给STM32下载代码 此处以...方法:见原子STM32F开发指南,3.4.1 STM32 串口程序下载。 简要说明: 1、RXD和PA9(stm32的TXD),TXD和PA10(stm32的RXD)通过跳线帽相连。实际就是把CH340G与MCU的串口1连接... -
simulink/STM32CubeMX联合生成STM32串口发送代码
2020-01-10 15:22:45项目需求,最近刚开始学习用simulink自动生成C代码,通过Keil编译并下载到STM...simulink/STM32CubeMX联合生成STM32串口发送代码,Keil编译下载到单片机,发送给上位机显示 1.在CubeMX里设置好相关参数后,在simul... -
stm32 串口中断总结
2018-05-13 15:51:15转载--------- stm32 串口中断总结 - 【stm32/stm8】 - 电子工程世界-论坛 http://bbs.eeworld.com.cn/thread-376382-1-1.html本文以USART1为例,叙述串口中断的编程过程。1、先来讲述一下在应用串口中断时涉及到... -
STM32串口通信学习总结
2020-09-09 17:30:42STM32串口通信学习总结 1.概述 1.1学习目的 通过基于AWA5812平台,学习STM32F767芯片的串口通信程序开发。本人学习串口通信比较曲折,一开始使用的芯片时STM32新开发出来的一块STM32L496ZG的板子,这块板子的优点... -
STM32 串口及奇偶校验问题
2019-07-02 17:43:38背景说明: STM32上对接一款串口传感器,该串口采用串口如下 波特率:115200 停止位:1 校验位:偶校验(Even) 硬件流控:无 数据位:8bit 笔者使用STM32F103C8系列单片机,使用2路串口 ...2、STM32串口2... -
一个严谨的STM32串口DMA发送&接收(1.5Mbps波特率)机制
2020-09-03 23:54:58本文描述串口DMA收/发机制设计,及STM32串口DMA收/发实现。 -
stm32串口1串口2 DMA方式收发数据
2014-08-15 22:58:24stm32串口1串口2,DMA方式收发数据。使用定时器定时查询DMA接收到的数据,当串口的数据空闲中断,将数据拷贝到缓冲区,交由其他程序处理。可以接收任意大小的数据包。本方法占用CPU时间极少,尤其是波特率很高时,... -
STM32串口接收字符串并控制LED
2018-08-05 11:32:50通过STM32 串口1 接收字符串实现LED控制,程序通过判断\n识别字符串是否发送完成,所以串口调试助手上需勾选发送新行,发送LED1+ON点亮LED1,发送LED1+OFF关闭LED1,发送其他字符串翻转LED2 -
STM32 串口ISP下载方式解读
2017-12-13 11:22:48STM32 串口ISP下载方式解读 -
STM32串口连续接收一帧数据
2015-08-31 08:26:49STM32串口接收一帧数据的写法,数据包括帧头,功能帧,数据帧,校验位! -
STM32串口调试进入死循环
2019-09-05 09:36:44STM32串口调试进入死循环 最近在调试STM32串口,发现串口发送数据总是进入如下死循环 while(USART_GetFlagStatus(UART5, USART_FLAG_TXE) == RESET); 经检查发现串口时钟没有开,打开串口时钟后串口发送数据正常 ... -
STM32串口通信以及C语言程序在Keil中针对stm32系统进行编程
2020-12-01 13:54:04STM32串口通信以及C语言程序在Keil中针对stm32系统进行编程基于寄存器与基于固件库的stm32 LED流水灯例子的编程方式有什么差异。1.从两个使用过的角度来讲:2.从直观角度来讲:3.从实际操作来讲:STM32的USART窗口... -
stm32串口程序
2018-03-22 09:10:55stm32串口程序(全)2012-04-13 00:00 困扰了我N就的串口问题终于在昨天下午解决了,那叫一个开心啊,哈哈。开心之余又有点沮丧,应为东拼西凑下来的程序,虽然跑通了,但是还有一些地方看不明白,算了,还是先记录... -
stm32串口无法识别
2016-05-10 13:17:39stm32串口出现如下的错误 1.解决方案 从http://www.ac6-tools.com/downloads//SW4STM32/ download并安装install_sw4stm32_win_32bits-latest.exe -
stm32串口基本配置
2018-08-05 14:36:50STM32串口基本配置 1 时钟使能(用到哪个串口和GPIO要把相应的时钟开启); 2 串口复位;(一般在系统刚开始配置外设的时候,都会先执行复位该外设的操作。) 3 GPIO口配置; 4 串口参数配置; 5 根据需要开启... -
stm32串口通信
2015-12-07 16:42:06通信方式 1、同步通信:带时钟同步信号传输 SPI,IIC等 2、异步通信:不带时钟用途信号 USRT,单总线 stm32串口引脚表 串口号 RXD TXD 1 PA10 PA9 2 PA3 PA2 3 PB11 PB10 -
使用STM32CubeMX配置STM32串口
2020-07-07 11:48:05第一步:打开STM32CubeMX,选择使用的STM32控制器 第二步,选择使用的STM32控制器 第三步,设置工程名和保存目录第四步,设置Code Generator,按照如图设置可以自动获得按配置整理好的代码 第五步,配置时钟 第六步... -
STM32 串口接收不定长字节数据
2019-06-28 14:37:29STM32 串口接收不定长字节数据(基于空闲终端+接收中断) -
STM32串口通信乱码详细处理方法
2018-01-13 10:26:24STM32串口通信以及温度采集搞定,其中主要遇到STM32系列单片机时钟树的问题,串口通信遇到串口调试助手能够接收到数据但出现乱码现象,开始一直以为是串口配置和程序代码问题,因为是第一次上电在线调试STM32板子,...