- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
您好,我目前正在研究 USART 通信,试图从任何 GPIO 引脚传输和接收数据。
我成功地以任何波特率传输数据,但在接收时卡住了。
我一次能收到一个角色。引脚设置为使用 RX 引脚的外部下降沿中断。
但是当我从终端向 Controller 传输像“test”这样的字符串时,只接收到“t”,剩下的 3 个字符是垃圾值。我在想,在接收到第一个字符并保存它之后,下一个字符的中断触发速度不会那么快。
出于测试目的,此示例代码中的许多内容都是硬编码的。
这里是接收者的示例代码
void EXTI0_IRQHandler(void){
r0 = GPIOA->IDR;
delay_us(delay_time);
r1 = GPIOA->IDR;
delay_us(delay_time);
r2 = GPIOA->IDR;
delay_us(delay_time);
r3 = GPIOA->IDR;
delay_us(delay_time);
r4 = GPIOA->IDR;
delay_us(delay_time);
r5 = GPIOA->IDR;
delay_us(delay_time);
r6 = GPIOA->IDR;
delay_us(delay_time);
r7 = GPIOA->IDR;
delay_us(delay_time);
r8 = GPIOA->IDR;
delay_us(delay_time);
r9 = GPIOA->IDR;
delay_us(delay_time);
r1 = r1 & 0x00000001;
r2 = r2 & 0x00000001;
r3 = r3 & 0x00000001;
r4 = r4 & 0x00000001;
r5 = r5 & 0x00000001;
r6 = r6 & 0x00000001;
r7 = r7 & 0x00000001;
r8 = r8 & 0x00000001;
x |= r8;
x = x << 1;
x |= r7;
x = x << 1;
x |= r6;
x = x << 1;
x |= r5;
x = x << 1;
x |= r4;
x = x << 1;
x |= r3;
x = x << 1;
x |= r2;
x = x << 1;
x |= r1;
buff1[z++] = x;
EXTI->PR |= 0X00000001;
x=0;
return ;}
感谢您的帮助。
最佳答案
您的解决方案的根本问题是您在过渡点而不是位中心对位进行采样。在检测到 START 转换时,您仅延迟一位周期,因此在位转换而不是位 centre 处采样 r1
- 这几乎肯定会导致错误,尤其是在边缘可能不是很快的高速下。第一个延迟应为 1.5 位周期长。 (delay_time * 2/3
) 如下图所示:
第二个问题是您在 STOP 位之后不必要地延迟,这将导致您错过下一个 START 转换,因为它可能发生在您清除中断标志之前。一旦拥有 r8
,您的工作就完成了。
采样 r0
和 r9
在任何情况下都不会丢弃它们,并且状态 r0
隐含在 EXTI 的任何事件中如果发送方生成无效帧,则 r9
不会为 1。此外,如果您不对 r9
进行采样,则它之前的延迟也变得不必要了。这些行应该被删除:
delay_us(delay_time);
r9 = GPIOA->IDR;
delay_us(delay_time);
这至少会给你两个位周期,让你的处理器可以做其他工作而不是卡在中断上下文中,但是延迟是一个中断处理程序不是一个好习惯 - 它会阻止正常代码和所有低优先级中断的执行使解决方案不适用于实时系统。在这种情况下,如果系统只需要软 UART Rx,那么通过简单地轮询 GPIO 而不是使用中断可能会获得更好的结果——至少其他中断可以正常运行,而且实现起来要简单得多.
你的“unrolled-loop”实现也没有真正的目的,延迟到位 - 即使在非常高的比特率下,循环开销在帧的持续时间内可能是微不足道的,如果是的话你可以调整延迟一点补偿:
void EXTI0_IRQHandler(void)
{
delay_us(delay_time * 2 / 3);
for( int i = 7; i >= 0; i-- )
{
x |= GPIOA->IDR << i ;
delay_us(delay_time);
}
EXTI->PR |= 0X00000001;
buff1[z++] = x;
x = 0 ;
return ;
}
一个更健壮的软接收器解决方案可以很好地与系统中的其他进程配合使用,应该只使用 EXTI 中断来检测起始位;处理程序应禁用 EXTI,并以波特率加半位周期启动定时器。定时器的中断处理程序在位周期的中心对 GPIO 引脚进行采样,并在 EXTI 之后的第一个中断上将周期更改为一位周期。对于每个定时器中断,它都会对位进行采样和计数,直到移入一个完整的数据字,此时它会禁用定时器并为下一个起始位重新启用 EXTI。
我已经在以 120MHz 和 4800 运行的 STM32 上成功地使用了这种技术,并将其推至 38400,但是在每比特 26 微秒时,它在中断上下文中变得非常繁忙,您的应用程序可能还有其他事情要做?
以下是我的实现的稍微通用化的版本。它使用 STM32 标准外设库调用,而不是直接寄存器访问或后来的 STM32Cube HAL,但您可以根据需要轻松地以一种或另一种方式移植它。框架是 N,8,1。
#define SOFT_RX__BAUD = 4800u ;
#define SOFT_RX_TIMER_RELOAD = 100u ;
void softRxInit( void )
{
// Enable SYSCFG clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
// Connect the EXTI Line to GPIO Pin
SYSCFG_EXTILineConfig( EXTI_PortSourceGPIOB, EXTI_PinSource0 );
TIM_Cmd( TIM10, DISABLE);
// NVIC initialisation
NVIC_InitTypeDef NVIC_InitStructure = {0,0,0,DISABLE};
NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_TIM10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
// Enable peripheral clock to timers
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM10, ENABLE);
TIM_ARRPreloadConfig( TIM10, DISABLE );
// Generate soft Rx rate clock (4800 Baud)
TIM_TimeBaseInitTypeDef init = {0};
TIM_TimeBaseStructInit( &init ) ;
init.TIM_Period = static_cast<uint32_t>( SOFT_RX_TIMER_RELOAD );
init.TIM_Prescaler = static_cast<uint16_t>( (TIM10_ClockRate() / (SOFT_RX__BAUD * SOFT_RX_TIMER_RELOAD)) - 1 );
init.TIM_ClockDivision = 0;
init.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit( TIM10, &init ) ;
// Enable the EXTI Interrupt in the NVIC
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 12;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );
// Dummy call to handler to force initialisation
// of UART frame state machine
softRxHandler() ;
}
// Soft UART Rx START-bit interrupt handler
void EXTI0_IRQHandler()
{
// Shared interrupt, so verify that it is the correct one
if( EXTI_GetFlagStatus( EXTI_Line0 ) == SET )
{
// Clear the EXTI line pending bit.
// Same as EXTI_ClearITPendingBit( EXTI_Line11 )
EXTI_ClearFlag( EXTI_Line0 ) ;
// Call Soft UART Rx handler
softRxHandler() ;
}
}
void TIM1_UP_TIM10_IRQHandler( void )
{
// Call Soft UART Rx handler
softRxHandler() ;
TIM_ClearITPendingBit( TIM10, TIM_IT_Update );
}
// Handler for software UART Rx
inline void softRxHandler()
{
static const int START_BIT = -1 ;
static const int STOP_BIT = 8 ;
static const int HALF_BIT = SOFT_RX_TIMER_RELOAD / 2;
static const int FULL_BIT = SOFT_RX_TIMER_RELOAD ;
static int rx_bit_n = STOP_BIT ;
static const uint8_t RXDATA_MSB = 0x80 ;
static uint8_t rx_data = 0 ;
static EXTI_InitTypeDef extiInit = { EXTI_Line0,
EXTI_Mode_Interrupt,
EXTI_Trigger_Falling,
DISABLE } ;
// Switch START-bit/DATA-bit
switch( rx_bit_n )
{
case START_BIT :
{
// Stop waiting for START_BIT
extiInit.EXTI_LineCmd = DISABLE;
EXTI_Init( &extiInit );
// Enable the Interrupt
TIM_ClearITPendingBit( TIM10, TIM_IT_Update );
TIM_ITConfig( TIM10, TIM_IT_Update, ENABLE );
// Enable the timer (TIM10)
// Set time to hit centre of data LSB
TIM_SetAutoreload( TIM10, FULL_BIT + HALF_BIT ) ;
TIM_Cmd( TIM10, ENABLE );
// Next = LSB data
rx_data = 0 ;
rx_bit_n++ ;
}
break ;
// STOP_BIT is only set on first-time initialisation as a state, othewise it is
// transient within this scase.
// Use fall through and conditional test to allow
// case to handle both initialisation and UART-frame (N,8,1) restart.
case STOP_BIT :
default : // Data bits
{
TIM_ClearITPendingBit( TIM10, TIM_IT_Update );
if( rx_bit_n < STOP_BIT )
{
if( rx_bit_n == 0 )
{
// On LSB reset time to hit centre of successive bits
TIM_SetAutoreload( TIM10, FULL_BIT ) ;
}
// Shift last bit toward LSB (emulate UART shift register)
rx_data >>= 1 ;
// Read Rx bit from GPIO
if( GPIO_ReadInputDataBit( GPIOB, GPIO_Pin_0 ) != 0 )
{
rx_data |= RXDATA_MSB ;
}
// Next bit
rx_bit_n++ ;
}
// If initial state or last DATA bit sampled...
if( rx_bit_n == STOP_BIT )
{
// Stop DATA-bit sample timer
TIM_Cmd( TIM10, DISABLE );
// Wait for new START-bit
rx_bit_n = START_BIT ;
extiInit.EXTI_LineCmd = ENABLE;
EXTI_Init( &extiInit );
// Place character in Rx buffer
serialReceive( rx_data ) ;
}
}
break ;
}
}
代码的工作方式与上面时序图中所示的真实 UART 相同,但在我的实现中实际上并未对 STOP 位进行采样——这是不必要的;它仅用于确保后续的 START 位是 1 -> 0 转换,通常可以忽略。如果它不是 1,一个真正的 UART 可能会产生一个帧错误,但如果您在任何情况下都不打算处理此类错误,那么检查就没有意义。
关于c - STM32 上的 USART 接收器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55256101/
媒体存在于外部服务器上,我想在我的 Actor 接收器上播放该媒体( Google's CastReferencePlayer 的修改版本)。接收器与该服务器持续通信(通过长轮询),并在需要播放某个媒
我想将我的 PyQt4 应用程序移植到 PyQt5,但遇到了一个微妙的问题。 有时我会检查自定义 QThread 对象 (worker) 是否仍然连接了一些特定的信号,我在 PyQt4 中已经这样做了
假设我们有 n 台设备,n 为偶数。每个设备都可以作为发射器 (T) 或接收器 (R)。对于每个设备 i,我们都给定了 2 个数字,Ti 和 Ri。 Ti 是设备用作发射器时的成本,Ri 是设备用作接
我想在 android 中创建 airplay,其中我的 android 设备将用作 airplay 服务器(接收器),而 iPhone 设备将用作接收器。我在我的应用程序中使用了 jmdns,它是
简单问题 - 我可以将单个 BroadcastReceiver 注册到多个 Intent 操作吗?这是我正在考虑的: 所以在 myRecei
假设我在 2 个应用程序(应用程序 A 和应用程序 B)的 list 中有以下接收器: 在每个应用程序中,我想创建一个 PendingIntent(如果不存在
我正在尝试向接收方应用程序的关闭事件添加逻辑,但每次发送方断开连接时,调试器都会关闭并且不会执行任何逻辑(例如发送一些 HttpRequest)。我的一段代码: this.context.addEve
我们正在使用flume,我需要将一些日志消息收集到rabbitmq 中。我找到了一个来源 implementation从rabbitmq读取消息,但我找不到可以将消息写入rabbit的接收器。所以我想
我遇到了一个远程异常: “这个远程代理没有 channel 接收器,这意味着服务器没有注册的服务器 channel 正在监听,或者这个应用程序没有合适的客户端 channel 来与服务器通信。” th
我是 WebRTC 的新手,并试图弄清楚如何在浏览器之外创建一个程序,该程序接收 WebRTC 音频流并将其输出到扬声器上。 是否有适用于 Java 或 C# 的 WebRTC 库? 该接收器将在 l
我正在创建一个简单的 Spring Boot 应用程序,我想接收发送到 AMQP(Rabbit)交换(来自另一个应用程序)的消息。 我收到一条错误消息,指出我要接收的队列不存在。当我看 http://
我将 EJB 3.0 与 JBoss AS 7.1.1 Final 一起使用。当我尝试将客户端连接到服务器时出现此错误: Aug 15, 2012 12:05:00 PM org.jboss.ejb.
我正在为 Google Cast SDK 使用 React Native 包装器,但无法从发送方向接收方发送消息。我能够转换媒体或暂停并恢复它。问题仅在于自定义消息。我的自定义消息监听器永远不会在接收
我正在开发自定义 Serilog 接收器,它继承自 PeriodicBatchingSink 并调用我的网络服务将数据写入数据库,使用类似于 Serilog.Sinks.Seq 的模式。使用此代码作为
我想为安卓手机开发一个定制的 FM radio 应用程序,里面有 FM 接收芯片。 通过研究,我发现 FM 接收器通常由 BroadComm 开发。 主要的安卓手机制造商——三星、HTC、索尼爱立信是
我的 android list 中有一个 Intent 接收器,但我想让用户有机会选择他/她是否希望应用程序在特定状态下自动启动。到目前为止,我一直在使用带有广播接收器的服务,但我真的很想删除这个服务
我正在做一个如果我们摇动手机就锁屏的应用程序,我已经写了屏幕关闭的代码,但现在的问题是我需要一个广播接收器来检查屏幕是关闭还是打开,我怎么能做吗? 最佳答案 如果您需要在特定时刻检查屏幕是否关闭或打开
我让 MySQL 在一页上生成具有相同操作和提交按钮的表单。表格的数量各不相同。它们在提交时都调用同一个 PHP 文件。另外,我有一个 PHP 文件,它在提交时收集数据。请参见下面的示例。 问题是当提
谁能给我一个例子,说明如何在 Activity 类中正确取消注册 LocalBroadcastManager 接收器? Android 开发人员培训建议这样做: @Override publ
有问题的代码: func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
我是一名优秀的程序员,十分优秀!