之前一直用的固件库跑c8t6和zet6,现在有幸接触到stm32H743用到HAL库,学习嘛都是踩坑,csdn,然后...理解底层库的代码
本人有幸遇到了H7的串口中断接收只进去一次的Bug,于是马上csdn,才发现网上全是在回调函数里写接收处理的逻辑,而我不一样,可能我比你们帅我就要把接收逻辑写在中断服务函数里面(狗头),其实是因为最先接触的板子是103的c8t6所有例程都是在服务函数里处理的,所有养成了习惯,做H7的工程时就直接移植了;但找了2天我也没在网上没有找到将逻辑写在服务函数里面的,于是乎,花费一天时间看HAL库的串口驱动程序,终于!调通了,话不多说,
上!代!码!
串口初始化和固件库的配置逻辑大体一样:
void UART2_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_PeriphCLKInitTypeDef RCC_PeriphClkInit;
UART2_RX_GPIO_CLK_ENABLE();
UART2_TX_GPIO_CLK_ENABLE();
/* 配置串口2时钟源*/
RCC_PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART2;
RCC_PeriphClkInit.Usart16ClockSelection = RCC_USART16CLKSOURCE_D2PCLK2;
HAL_RCCEx_PeriphCLKConfig(&RCC_PeriphClkInit);
/* 使能 UART2 时钟 */
UART2_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
/* 配置Tx引脚为复用功能 */
GPIO_InitStruct.Pin = UART2_TX_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = UART2_TX_AF;
HAL_GPIO_Init(UART2_TX_GPIO_PORT, &GPIO_InitStruct);
/* 配置Rx引脚为复用功能 */
GPIO_InitStruct.Pin = UART2_RX_PIN;
GPIO_InitStruct.Alternate = UART2_RX_AF;
HAL_GPIO_Init(UART2_RX_GPIO_PORT, &GPIO_InitStruct);
/* 配置串USART2 模式 */
Uart2_Handle.Instance = UART2;
Uart2_Handle.Init.BaudRate = 115200;
Uart2_Handle.Init.WordLength = UART_WORDLENGTH_8B;
Uart2_Handle.Init.StopBits = UART_STOPBITS_1;
Uart2_Handle.Init.Parity = UART_PARITY_NONE;
Uart2_Handle.Init.Mode = UART_MODE_TX_RX;
HAL_UART_Init(&Uart2_Handle);
/*串口2中断初始化 */
HAL_NVIC_SetPriority(UART2_IRQ, 0, 3);
HAL_NVIC_EnableIRQ(UART2_IRQ);
/*配置串口接收中断 */
__HAL_UART_ENABLE_IT(&Uart2_Handle,UART_IT_RXNE);
}
/**
* @brief UART2 GPIO 配置,工作模式配置。115200 8-N-1
*/
需要注意调用 __HAL_UART_ENABLE_IT(&Uart2_Handle,UART_IT_RXNE)函数使能中断。
接下来是中断服务函数的编写:
unsigned char SHU1[42]={0}; //接收缓存
unsigned char ces[1];
unsigned char MODE=0;
u8toointt pos1,pos2,pos3,pos4,pos5,pos6;
float posBi[7]={0,0,0,0,0,0,0};//机械臂角度
void UART2_IRQHandler(void)
{
static unsigned char conunt=0; // 接收记录
static unsigned char i = 0; //记录数据个数
static unsigned char j = 0;
uint32_t timeout=0;
uint32_t maxDelay=0x1FFFF;
//调用HAL_UART_Receive_IT函数进行接收可再次开启中断
HAL_UART_IRQHandler(&Uart2_Handle); //调用HAL库中断处理公用函数
timeout=0;
while (HAL_UART_GetState(&Uart2_Handle)!=HAL_UART_STATE_READY)//等待就绪
{
timeout++;超时处理
if(timeout>maxDelay) break;
}
timeout=0;
while(HAL_UART_Receive_IT(&Uart2_Handle,(uint8_t *)ces, 1)!=HAL_OK)//一次处理完成之后,重新开启中断并设置RxXferCount为1
{
timeout++; //超时处理
if(timeout>maxDelay) break;
}
//处理接收到的一个字节
switch(conunt)
{
case 0:
if(ces[0] == 0xFF) conunt++;
else conunt=0;
break;
case 1:
if(ces[0] == 0xFF) conunt ++; //数据帧头
else conunt = 0;
break;
case 2://角度包
SHU1[i] = ces[0];
i++;
if(i==6)//接收完成了开始验证
{
if(SHU1[5]==0xFE)//判断数据帧尾
{
switch(SHU1[0])
{
case 0x01:
for(j=0;j<=3;j++) //pos1角度接收
{
pos1.Receive_Val[j]=SHU1[j+1];
}
posBi[1]=pos1.Act_val;
break;
case 0x02:
for(j=0;j<=3;j++) //pos2角度接收
{
pos2.Receive_Val[j]=SHU1[j+1];
}
posBi[2]=pos2.Act_val;
break;
case 0x03:
for(j=0;j<=3;j++) //pos3角度接收
{
pos3.Receive_Val[j]=SHU1[j+1];
}
posBi[3]=pos3.Act_val;
break;
case 0x04:
for(j=0;j<=3;j++) //pos4角度接收
{
pos4.Receive_Val[j]=SHU1[j+1];
}
posBi[4]=pos4.Act_val;
break;
case 0x05:
for(j=0;j<=3;j++) //pos5角度接收
{
pos5.Receive_Val[j]=SHU1[j+1];
}
posBi[5]=pos5.Act_val;
break;
case 0x06:
for(j=0;j<=3;j++) //pos6角度接收
{
pos6.Receive_Val[j]=SHU1[j+1];
}
posBi[6]=pos6.Act_val;
break;
case 0x07://模式控制
MODE=SHU1[1]-0x30;
}
}
conunt = 0;
i = 0;
}
break;
}
大家可以看见,本帅哥的处理逻辑是一个字节一个字节地进行,这里的逻辑是用来接收上位机发来的6个角度的,在上位机先将角度(小数)放在共用体的float 类型成员变量中,然后发送角度的 unsigned char 类型成员变量
共用体定义如下:
typedef union
{
unsigned char Receive_Val[3];
float Act_val;
}u8toointt;
一个小数4个字节,所以对应4个字符型变量储存,然后32这边也定义一个共用体,用unsigned char 类型成员变量去接收,解出他的float 类型成员变量,便是我想要的角度了,怎么样,这一波我帅吧?
突然发现跑题了,来看看我们是怎么解决中断只进去一次的问题的:
官方给的中断接收的逻辑是写在回调函数里的,为什么写在回调函数里面呢?
看这篇文章:(14条消息) 那些我们一起踩过的STM32HAL库的串口坑_我又不会射雕的博客-CSDN博客
大概意思就是当有中断发送,硬件自动触发然后调用一系列函数,调用到 UART_Receive_IT()函数后,便会关闭中断!!!也就是串口看起来就只能进入一次中断!
有的小可爱可能会问我为什么我能一直进中断呢?我试过,当上位机发送很快,且每次发送的字节数较少时(大概1个),我怎么配置他都能进中断!可能UART_Receive_IT()函数关闭中断的条件是中断触发的间隔时间吧,这点我没细看~
当然有小可爱可能会说我像官方例程那样写,就什么问题都没有,我说小可爱,你可真可爱,没问题你来看我这篇文章干嘛,让我火吗???如果是,那给我点赞吧,不谢!我很帅!
回归正题:
注意看我的UART2_IRQHandler(void)函数里面接收函数用的HAL_UART_Receive_IT(&Uart2_Handle,(uint8_t *)ces, 1)!=HAL_OK
还有一种接收函数是HAL_UART_Receive(&huart2,&Res,1,1000);
它们两个处理名字差了三个字符外有什么区别呢?
关键点来了:
一起来看这篇文章:(14条消息) STM32采用HAL库HAL_UART_Receive_IT()多次开启的问题_暖暖_的_纠结的博客-CSDN博客_hal_uart_receive_it
无情的文章搬运小天才(滑稽)~
没看懂?解释一下我的理解:
HAL_UART_Receive函数为非阻塞式接收,HAL_UART_Receive_IT()为阻塞式接收,说人话就是调用HAL_UART_Receive_IT()函数,一旦中断来了就能接收(前提是中断使能了),而HAL_UART_Receive则不一样,用在接收的地方卵用没有,简直消磨帅哥的时间~哼~
所以我们使用HAL_UART_Receive_IT()函数,如果我们需要判断接收超时怎么办?我去官方例程copy了一下自己看上面 (^-^)
这样写以后,帅哥再也不用担心H7串口进不去中断了,完美避开回调函数的写法,帅哥可高兴了,马上去食堂买一个水煮玉米奖励自己~~~
然后你肯定想要移植,我这个工程肯定不会完全给你,但是可以给你这个串口接收的文件,欢迎期待我的github链接~
我正在处理旧代码的一部分。beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)endRubocop错误如下:Avoidstubbingusing'allow_any_instance_of'我读到了RuboCop::RSpec:AnyInstance我试着像下面那样改变它。由此beforedoallow_any_instance_of(SportRateManager).toreceive(:create).and_return(true)end对此:let(:sport_
我有一个非常简单的RubyRack服务器,例如:app=Proc.newdo|env|req=Rack::Request.new(env).paramspreq.inspect[200,{'Content-Type'=>'text/plain'},['Somebody']]endRack::Handler::Thin.run(app,:Port=>4001,:threaded=>true)每当我使用JSON对象向服务器发送POSTHTTP请求时:{"session":{"accountId":String,"callId":String,"from":Object,"headers":
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
SPI接收数据左移一位问题目录SPI接收数据左移一位问题一、问题描述二、问题分析三、探究原理四、经验总结最近在工作在学习调试SPI的过程中遇到一个问题——接收数据整体向左移了一位(1bit)。SPI数据收发是数据交换,因此接收数据时从第二个字节开始才是有效数据,也就是数据整体向右移一个字节(1byte)。请教前辈之后也没有得到解决,通过在网上查阅前人经验终于解决问题,所以写一个避坑经验总结。实际背景:MCU与一款芯片使用spi通信,MCU作为主机,芯片作为从机。这款芯片采用的是它规定的六线SPI,多了两根线:RDY和INT,这样从机就可以主动请求主机给主机发送数据了。一、问题描述根据从机芯片手
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie
在几个项目中,我希望有一个类似rakeserver的rake任务,它将通过任何需要的方式开始为该应用程序提供服务。这是一个示例:task:serverdo%x{bundleexecrackup-p1234}end这行得通,但是当我准备停止它时,按Ctrl+c并没有正常关闭;它中断了Rake任务本身,它说rakeaborted!并给出堆栈跟踪。在某些情况下,我必须执行Ctrl+c两次。我可能可以用Signal.trap写一些东西来更优雅地中断它。有没有更简单的方法? 最佳答案 trap('SIGINT'){puts"Yourmessa
我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.
我很难理解Ruby中sender和receiver的实际含义。它们一般是什么意思?到目前为止,我只是将它们理解为方法调用和获取其返回值的调用。但是,我知道我的理解还远远不够。谁能给我一个Ruby中发送者和接收者的具体解释? 最佳答案 面向对象中的一个核心概念是消息传递和早期概念化,这在很大程度上借鉴了计算的Actor模型。艾伦·凯(AlanKay)创造了面向对象一词并发明了最早的OO语言之一SmallTalk,他拥有voicedregretatusingatermwhichputthefocusonobjectsinsteadofo
一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su