Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
软件IO模拟串口UART
系统中断
硬实时
30
在RTT下使用普通IO口模拟串口时序,如何才能做到不被系统干扰?
发布于 2020-07-08 17:14:01 浏览:1895
订阅该版
[tocm] ##### 问题背景 板载资源已经使用完,但是还需要一组额外的串口。只能使用IO口来自己写时序,模拟串口收发。 考虑过使用DMA的方式来进行接收/发送,但是已经没有硬件资源了。 ##### 开发环境 单片机:STM32F103RET6 系统:RT-Thread 模拟收发的引脚:TX--PB14 RX--PB15 接收定时器:TIM6 发送定时器:TIM5 ##### 问题描述 在裸机上已经测试过收发功能,很稳定,基本没有误码。 移植到RT-Thread下之后发现误码率较高。 最初是怀疑两个定时器的中断优先级比较低,被系统干扰导致,就全局搜索中断设置,把所有的(0,0)组都改为了(0,1),只保留我的两个定时器为(0,0)。测试波形发现还是进入定时器中断的时间不稳定,时快时慢。 下图是用示波器测试的中断进入状况,我是每次进入定时器中断就反转一个引脚的状态。 ![9f18709363795af7a09ecc69a7163d5.png](/uploads/20200708/74477b7fc13193349f4028d7e0b24632.png) 可以很清晰的看到进入中断的时间确实不是那么准时。 求教到底是什么原因导致了我的中断会延时进入?或者说如何把我的自己的中断优先级调到最高,不被系统干扰到? 附上我的代码。 ``` /** * @file emul.c * @author roger (mrshaorong@gmail.com) * @brief * @version 0.1 * @date 2020-07-02 * * @copyright Copyright (c) 2020 * */ #include
#include
#include
#include "stm32f1xx_hal.h" #include "drv_usart.h" #define BuadRate_9600 #ifdef BuadRate_9600 #define BUADRATE_PRESCALER 71 #define BUADRATE_PERIOD 103 #endif #define RX_PIN GET_PIN(B, 15) #define TX_PIN GET_PIN(B, 14) #define TX_HIGH (GPIOB->BSRR = GPIO_PIN_14) #define TX_LOW (GPIOB->BRR = GPIO_PIN_14) #define OI_RXD rt_pin_read(RX_PIN) #define RECV_BUF_MAX 0xFF TIM_HandleTypeDef htim6; TIM_HandleTypeDef htim5; #define DBG_TAG "OPENMV" #define DBG_LVL DBG_LOG #include
uint8_t SW_Usart_Recv_Len = 0; uint64_t SW_Usart_Recv_Write = 0; uint64_t SW_Usart_Recv_Read = 0; uint8_t SW_Usart_Recv_Buf[RECV_BUF_MAX] = { 0 }; enum { COM_START_BIT, COM_D0_BIT, COM_D1_BIT, COM_D2_BIT, COM_D3_BIT, COM_D4_BIT, COM_D5_BIT, COM_D6_BIT, COM_D7_BIT, COM_STOP_BIT, }; uint8_t recvStat = COM_STOP_BIT; uint8_t recvData = 0; uint8_t SendBitBuf[10] = { 0 }; uint8_t SendPos = 0; uint8_t SendOverFlag = 0; /* 指向互斥量的指针 */ static rt_mutex_t sw_uart_write_mutex = RT_NULL; void IO_TXD(uint8_t Data) { static uint16_t wait_send_times = 0; rt_mutex_take(sw_uart_write_mutex, RT_WAITING_FOREVER); TX_HIGH; // SendBitBuf[0] = 0; for (size_t i = 1; i < 9; i++) { SendBitBuf[i] = (Data >> (i - 1)) & 0x01; } SendBitBuf[COM_STOP_BIT] = 1; // 开始发送 SendOverFlag = 0; SendPos = 1; wait_send_times = 2400; // 500:208.9us;1000:417.3us;2000:843.08us HAL_TIM_Base_Start_IT(&htim5); TX_LOW; // 最多等待9600波特率的发送1byte间隔 while (!SendOverFlag && wait_send_times--) { } rt_mutex_release(sw_uart_write_mutex); } void USART_Send(uint8_t *buf, uint8_t data_len) { for (uint8_t t = 0; t < data_len; t++) { IO_TXD(buf[t]); } } /** * @brief TIM6 Initialization Function * @param None * @retval None */ static void MX_TIM6_Init(void) { TIM_MasterConfigTypeDef sMasterConfig = { 0 }; htim6.Instance = TIM6; htim6.Init.Prescaler = BUADRATE_PRESCALER; htim6.Init.CounterMode = TIM_COUNTERMODE_UP; htim6.Init.Period = BUADRATE_PERIOD; htim6.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim6) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim6, &sMasterConfig) != HAL_OK) { Error_Handler(); } HAL_NVIC_SetPriority(TIM6_IRQn, 0, 0); } /** * @brief TIM5 Initialization Function * @param None * @retval None */ static void MX_TIM5_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = { 0 }; TIM_MasterConfigTypeDef sMasterConfig = { 0 }; htim5.Instance = TIM5; htim5.Init.Prescaler = BUADRATE_PRESCALER; htim5.Init.CounterMode = TIM_COUNTERMODE_UP; htim5.Init.Period = BUADRATE_PERIOD; htim5.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim5.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim5) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim5, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim5, &sMasterConfig) != HAL_OK) { Error_Handler(); } HAL_NVIC_SetPriority(TIM5_IRQn, 0, 0); } #define TEST_PIN GET_PIN(B, 12) #define TEST_PIN1 GET_PIN(B, 13) /** * @brief This function handles TIM7 global interrupt. */ void TIM5_IRQHandler(void) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_13); if (HAL_TIM_Base_GetState(&htim5) != HAL_TIM_STATE_RESET) { __HAL_TIM_CLEAR_IT(&htim5, TIM_IT_UPDATE); if (SendBitBuf[SendPos]) { TX_HIGH; } else { TX_LOW; } SendPos++; if (SendPos > COM_STOP_BIT) { TX_HIGH; SendOverFlag = 1; HAL_TIM_Base_Stop_IT(&htim5); return; } } } /** * @brief This function handles TIM6 global interrupt. */ void TIM6_IRQHandler(void) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12); // rt_uint32_t level; // level = rt_hw_interrupt_disable(); recvStat++; if (HAL_TIM_Base_GetState(&htim6) != HAL_TIM_STATE_RESET) { __HAL_TIM_CLEAR_IT(&htim6, TIM_IT_UPDATE); if (recvStat == COM_STOP_BIT) { HAL_TIM_Base_Stop_IT(&htim6); rt_pin_irq_enable(RX_PIN, PIN_IRQ_ENABLE); // EXTI->IMR |= GPIO_PIN_15; if (SW_Usart_Recv_Len >= RECV_BUF_MAX) { // LOG_D("SW_Usart_Recv_Len > %d", RECV_BUF_MAX); return; } SW_Usart_Recv_Buf[(SW_Usart_Recv_Write++) % RECV_BUF_MAX] = recvData; SW_Usart_Recv_Len++; // rt_hw_serial_isr(&uart_sw_obj.serial, RT_SERIAL_EVENT_RX_IND); } if (OI_RXD) { recvData |= (1 << (recvStat - 1)); } else { recvData &= ~(1 << (recvStat - 1)); } } } // /** // * @brief This function handles TIM6 global interrupt. // */ // void TIM6_IRQHandler(void) // { // HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12); // // rt_uint32_t level; // // level = rt_hw_interrupt_disable(); // if (HAL_TIM_Base_GetState(&htim6) != HAL_TIM_STATE_RESET) { // __HAL_TIM_CLEAR_IT(&htim6, TIM_IT_UPDATE); // if (recvStat == COM_START_BIT) { // // __HAL_TIM_SET_AUTORELOAD(&htim6, BUADRATE_PERIOD); // } // // else if (recvStat == COM_STOP_BIT) { // // rt_pin_irq_enable(RX_PIN, PIN_IRQ_ENABLE); // // HAL_TIM_Base_Stop_IT(&htim6); // // // EXTI->IMR |= GPIO_PIN_15; // // if (SW_Usart_Recv_Len >= RECV_BUF_MAX) { // // // LOG_D("SW_Usart_Recv_Len > %d", RECV_BUF_MAX); // // return; // // } // // SW_Usart_Recv_Buf[(SW_Usart_Recv_Write++) % RECV_BUF_MAX] = // // recvData; // // SW_Usart_Recv_Len++; // // // rt_hw_serial_isr(&uart_sw_obj.serial, RT_SERIAL_EVENT_RX_IND); // // return; // // } // else { // if (OI_RXD) { // recvData |= (1 << (recvStat - 1)); // } else { // recvData &= ~(1 << (recvStat - 1)); // } // } // recvStat++; // if (recvStat == COM_STOP_BIT) { // rt_pin_irq_enable(RX_PIN, PIN_IRQ_ENABLE); // HAL_TIM_Base_Stop_IT(&htim6); // // EXTI->IMR |= GPIO_PIN_15; // if (SW_Usart_Recv_Len >= RECV_BUF_MAX) { // // LOG_D("SW_Usart_Recv_Len > %d", RECV_BUF_MAX); // return; // } // SW_Usart_Recv_Buf[(SW_Usart_Recv_Write++) % RECV_BUF_MAX] = // recvData; // SW_Usart_Recv_Len++; // // rt_hw_serial_isr(&uart_sw_obj.serial, RT_SERIAL_EVENT_RX_IND); // } // } // } // void EXTI15_10_IRQHandler(void) // { // if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_15) != 0x00u) { // __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_15); // if (OI_RXD == 0) { // if (recvStat == COM_STOP_BIT) { // recvStat = COM_START_BIT; // HAL_TIM_Base_Start_IT(&htim6); // // EXTI->IMR &= ~GPIO_PIN_15; // // rt_pin_irq_enable(RX_PIN, PIN_IRQ_DISABLE); // } // } // } // } /* 中断回调函数 */ void beep_on(void *args) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_12); if (OI_RXD == 0) { if (recvStat == COM_STOP_BIT) { recvStat = COM_START_BIT; // __HAL_TIM_SET_AUTORELOAD(&htim6, BUADRATE_PERIOD / 2); // __HAL_TIM_SET_COUNTER(&htim6, BUADRATE_PERIOD / 2); HAL_TIM_Base_Start_IT(&htim6); rt_pin_irq_enable(RX_PIN, PIN_IRQ_DISABLE); } } } void IOConfig(void) { rt_pin_mode(TX_PIN, PIN_MODE_OUTPUT); rt_pin_mode(TEST_PIN, PIN_MODE_OUTPUT); rt_pin_mode(TEST_PIN1, PIN_MODE_OUTPUT); /* 按键0引脚为输入模式 */ rt_pin_mode(RX_PIN, PIN_MODE_INPUT_PULLUP); /* 绑定中断,上升沿模式,回调函数名为beep_on */ rt_pin_attach_irq(RX_PIN, PIN_IRQ_MODE_FALLING, beep_on, RT_NULL); /* 使能中断 */ rt_pin_irq_enable(RX_PIN, PIN_IRQ_ENABLE); } /** * @brief * * @param param */ static void sw_uart_thread(void *param) { rt_err_t res; TX_HIGH; rt_thread_mdelay(500); char ch = 0x00; IO_TXD(ch); while (1) { rt_thread_mdelay(1); if (SW_Usart_Recv_Len <= 10) { continue; } while (SW_Usart_Recv_Len) { SW_Usart_Recv_Len--; ch = SW_Usart_Recv_Buf[(SW_Usart_Recv_Read++) % RECV_BUF_MAX]; // LOG_D("RECV = %02X", ch); // ch++; IO_TXD(ch); rt_thread_mdelay(2); } } } static int sw_uart_init(void) { rt_thread_t tid; // 硬件设备初始化 IOConfig(); MX_TIM6_Init(); MX_TIM5_Init(); /* 创建一个动态互斥量 */ sw_uart_write_mutex = rt_mutex_create("sw_uart_mutex", RT_IPC_FLAG_FIFO); // tid = rt_thread_create("sw_uart", sw_uart_thread, RT_NULL, 1024, // (RT_THREAD_PRIORITY_MAX / 3), 10); tid = rt_thread_create("sw_uart", sw_uart_thread, RT_NULL, 1024, (5), 10); if (tid != RT_NULL) rt_thread_startup(tid); return RT_EOK; } INIT_APP_EXPORT(sw_uart_init); ```
查看更多
红枫
认证专家
2020-07-08
这家伙很懒,什么也没写!
操作系统会在处理临界区数据时关中断,单纯依靠在中断处理中收发数据是不行的,我以前使用定时器的输入捕获和比较输出功能做过模拟串口,9600速率是没问题的,看看你的收发引脚在不在定时器通道上。 提供一段红外口通信的驱动代码,是通过定时器模拟串口功能实现的,很久以前的代码了,使用的还是以前的stm32标准库,不过原理相同的,希望对你有所帮助. ```c //-------------------------------------------------------------------- //文件名 : IRComPort.c //创建人 : 齐永忠 //创建日期: 2009.10.29 //-------------------------------------------------------------------- #include "IRComPort.h" #include "Debug.h" #include "QQueue.h" //-------------------------------------------------------------------- #define IR_RX_PORT GPIOB #define IR_TX_PORT GPIOB #define IR_RX_PIN GPIO_Pin_1 #define IR_TX_PIN GPIO_Pin_0 #define IR_TX_NO 0 //红发发送脚对应脚号 #define IR_RX_TIMER TIM3//接收定时器定义 #define IR_TX_TIMER TIM2//发送定时器定义 #define IR_PWM_TIMER TIM3//PWM定时器定义 #define IR_RX_CHNNL TIM_IT_CC4//中断源 #define IR_TX_CHNNL TIM_IT_CC1//中断源 #define IR_PWM_CHNNL TIM_IT_CC3//中断源 #define IR_RX_CAP_CHNNL TIM_Channel_4//定时器信道,需与中断源一致 #define IR_PWM_CMD_CHNNL TIM_Channel_3//定时器信道,需与中断源一致 #define IRCOM_RX_IRQCHANNEL TIM3_IRQChannel//中断信道,需与定时器一致 #define IRCOM_TX_IRQCHANNEL TIM2_IRQChannel//中断信道,需与定时器一致 #define TIMER_PRESCALER 6// 定时器预分频值 #define IRCOM_BYTE_TIMEOUT 20 //红外口字节超时时间Ticks #define IRCOM_QUEUE_LEN 64//红外口队列长度 #define IRCOM_RX_QUEUE_PTR ((PQQUEUE)IRComRxQueue) //红外口队列指针 #define IRCOM_TX_QUEUE_PTR ((PQQUEUE)IRComTxQueue) //红外口队列指针 //-------------------------------------------------------------------- typedef struct{ u16 BitTClkNum; u16 BaudRate; u8 DataBit; u8 Parity:2; u8 StopBit:2; u8 ParityErr:1; u8 TxParity:1; u8 RxComMode:1; u8 RXStep:4; u8 TXStep:4; u8 RXChar; u8 TXChar; }IRCOMDATA; //-------------------------------------------------------------------- const u8 BitMask[] = {1<<0,1<<1,1<<2,1<<3,1<<4,1<<5,1<<6,1<<7}; const GPIO_InitTypeDef IRComRx = {IR_RX_PIN, GPIO_Speed_2MHz, GPIO_Mode_IN_FLOATING};//接收脚输入浮空 const GPIO_InitTypeDef IRComTx = {IR_TX_PIN, GPIO_Speed_2MHz, GPIO_Mode_IN_FLOATING};//发送脚复用功能开漏输出 const NVIC_InitTypeDef IRComRx_NVIC_InitStruct={IRCOM_RX_IRQCHANNEL, 0, 2, ENABLE}; const NVIC_InitTypeDef IRComTx_NVIC_InitStruct={IRCOM_TX_IRQCHANNEL, 0, 2, ENABLE}; const TIM_TimeBaseInitTypeDef IRTimerBaseCfg = {TIMER_PRESCALER-1, TIM_CounterMode_Up, 0xffff, TIM_CKD_DIV1, 0}; const TIM_ICInitTypeDef IRRxICCfg = {IR_RX_CAP_CHNNL, TIM_ICPolarity_Falling, TIM_ICSelection_DirectTI, TIM_ICPSC_DIV1, 0}; const TIM_OCInitTypeDef IRTROCCfg = {TIM_OCMode_Timing, TIM_OutputState_Disable, 0, 0, 0, 0, 0, 0}; const TIM_OCInitTypeDef IRTxPWMCfg= {TIM_OCMode_PWM1, TIM_OutputState_Enable, 0, 0, 0, 0, 0, 0}; //-------------------------------------------------------------------- static IRCOMDATA IRComData; static u8 IRComRxQueue[sizeof(QQUEUE)+IRCOM_QUEUE_LEN];//接收队列数据定义 static u8 IRComTxQueue[sizeof(QQUEUE)+IRCOM_QUEUE_LEN];//发送队列数据定义 //-------------------------------------------------------------------- static void SetPWMOutput(bool IsEnabled) { register u32 Cr; #if IR_TX_NO <= 7 Cr = IR_TX_PORT->CRL; #else Cr = IR_TX_PORT->CRH; #endif Cr &= ~(0x0000000F<<((IR_TX_NO%8)<<2)); if(IsEnabled) Cr |= (0x0000000E<<((IR_TX_NO%8)<<2)); else Cr |= (0x00000004<<((IR_TX_NO%8)<<2)); #if IR_TX_NO <= 7 IR_TX_PORT->CRL = Cr; #else IR_TX_PORT->CRH = Cr; #endif } //-------------------------------------------------------------------- static void TIM_OCxInit(TIM_TypeDef * TIMx, u16 TIM_Channel, TIM_OCInitTypeDef * TIM_OCInitStruct) { switch(TIM_Channel) { case TIM_IT_CC1: TIM_OC1Init(TIMx, TIM_OCInitStruct); break; case TIM_IT_CC2: TIM_OC2Init(TIMx, TIM_OCInitStruct); break; case TIM_IT_CC3: TIM_OC3Init(TIMx, TIM_OCInitStruct); break; case TIM_IT_CC4: TIM_OC4Init(TIMx, TIM_OCInitStruct); break; } } //-------------------------------------------------------------------- static void TIM_SetCompare(TIM_TypeDef * TIMx, u16 TIM_Channel, u16 Compare) { switch(TIM_Channel) { case TIM_IT_CC1: TIM_SetCompare1(TIMx, Compare); break; case TIM_IT_CC2: TIM_SetCompare2(TIMx, Compare); break; case TIM_IT_CC3: TIM_SetCompare3(TIMx, Compare); break; case TIM_IT_CC4: TIM_SetCompare4(TIMx, Compare); break; } } //-------------------------------------------------------------------- static u16 TIM_GetCapture(TIM_TypeDef * TIMx, u16 TIM_Channel) { switch(TIM_Channel) { case TIM_IT_CC1: return(TIM_GetCapture1(TIMx)); case TIM_IT_CC2: return(TIM_GetCapture2(TIMx)); case TIM_IT_CC3: return(TIM_GetCapture3(TIMx)); case TIM_IT_CC4: return(TIM_GetCapture4(TIMx)); } return(0); } //-------------------------------------------------------------------- static bool CalParity(u8 ch)//奇数个1返回true { ch^=(ch>>4); ch^=(ch>>2); ch^=(ch>>1); ch&=0x01; return((bool)(ch!=0)); } //-------------------------------------------------------------------- static void IRComPortSetRxModeCap(void)//设置为接收捕获模式 { TIM_ITConfig(IR_TX_TIMER,IR_TX_CHNNL,DISABLE);//禁止发送比较中断 TIM_Cmd(IR_TX_TIMER, DISABLE);//禁止发送定时器 TIM_Cmd(IR_PWM_TIMER, DISABLE);//禁能PWM定时器 IRComData.RxComMode = 0; TIM_ICInit(IR_RX_TIMER, (TIM_ICInitTypeDef *)&IRRxICCfg);//配置接收输入为下降沿捕获模式 TIM_SetAutoreload(IR_RX_TIMER, 0xffff);//设置自动重装寄存器 TIM_ClearITPendingBit(IR_RX_TIMER, IR_RX_CHNNL);//清中断标志 TIM_ITConfig(IR_RX_TIMER,IR_RX_CHNNL,ENABLE);//使能接收捕获中断 TIM_Cmd(IR_RX_TIMER, ENABLE);//使能接收定时器 } //-------------------------------------------------------------------- static void IRComPortRxCapToComp(void)//由捕获模式转换到比较模式 { static u16 CapVol; IRComData.RxComMode = 1; CapVol = TIM_GetCapture(IR_RX_TIMER, IR_RX_CHNNL)+IRComData.BitTClkNum/2; TIM_OCxInit(IR_RX_TIMER, IR_RX_CHNNL, (TIM_OCInitTypeDef *)&IRTROCCfg);//配置接收比较模式 TIM_SetCompare(IR_RX_TIMER, IR_RX_CHNNL, CapVol);//设置比较值 TIM_ClearITPendingBit(IR_RX_TIMER, IR_RX_CHNNL);//清中断标志 } //-------------------------------------------------------------------- static void IRComPortRxCompToCap(void)//由接收比较转换到接收捕获模式 { IRComData.RxComMode = 0; TIM_ICInit(IR_RX_TIMER, (TIM_ICInitTypeDef *)&IRRxICCfg);//配置接收输入为下降沿捕获模式 TIM_ClearITPendingBit(IR_RX_TIMER, IR_RX_CHNNL);//清中断标志 } //-------------------------------------------------------------------- static void IRComPortStartupSend(void)//红外口启动发送 { RCC_ClocksTypeDef RCC_Clocks; u32 TIM_Clocks; RCC_GetClocksFreq(&RCC_Clocks);//取时钟频率 if(RCC_Clocks.HCLK_Frequency == RCC_Clocks.PCLK1_Frequency) TIM_Clocks = RCC_Clocks.PCLK1_Frequency; else TIM_Clocks = RCC_Clocks.PCLK1_Frequency * 2; TIM_ITConfig(IR_RX_TIMER,IR_RX_CHNNL,DISABLE);//禁止接收捕获中断 TIM_Cmd(IR_PWM_TIMER, DISABLE);//禁能PWM定时器 TIM_OCxInit(IR_PWM_TIMER, IR_PWM_CHNNL, (TIM_OCInitTypeDef *)&IRTxPWMCfg);//配置PWM 定时器为PWM 模式 TIM_SetAutoreload(IR_PWM_TIMER, TIM_Clocks/38000/TIMER_PRESCALER);//设置自动重装寄存器,周期值 TIM_SetCompare(IR_PWM_TIMER, IR_PWM_CHNNL, TIM_Clocks/38000/TIMER_PRESCALER/2);//占空比50% TIM_SetCounter(IR_PWM_TIMER, 0);//设置计数器值 TIM_Cmd(IR_PWM_TIMER, ENABLE);//使能PWM定时器 IRComData.TXStep = 0; TIM_OCxInit(IR_TX_TIMER, IR_TX_CHNNL, (TIM_OCInitTypeDef *)&IRTROCCfg);//配置发送定时器为输出比较模式 TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCounter(IR_TX_TIMER)+IRComData.BitTClkNum);//设置发送比较值 TIM_ClearITPendingBit(IR_TX_TIMER, IR_TX_CHNNL);//清中断标志 TIM_ITConfig(IR_TX_TIMER,IR_TX_CHNNL,ENABLE);//使能发送比较中断 TIM_Cmd(IR_TX_TIMER, ENABLE);//使能发送定时器 } //-------------------------------------------------------------------- void IRComPortInit(u32 Baudrate, VERIFYBIT Verifybit, STOPBIT Stopbit) { RCC_ClocksTypeDef RCC_Clocks; u32 TIM_Clocks; RCC_GetClocksFreq(&RCC_Clocks);//取时钟频率 if(RCC_Clocks.HCLK_Frequency == RCC_Clocks.PCLK1_Frequency) TIM_Clocks = RCC_Clocks.PCLK1_Frequency; else TIM_Clocks = RCC_Clocks.PCLK1_Frequency * 2; IRComData.BaudRate = Baudrate; IRComData.DataBit = 8; IRComData.Parity = Verifybit; IRComData.StopBit = Stopbit; IRComData.ParityErr = 0; IRComData.RXStep = 0; IRComData.TXStep = 0; IRComData.BitTClkNum = TIM_Clocks/TIMER_PRESCALER/IRComData.BaudRate; QQInit(IRCOM_RX_QUEUE_PTR,sizeof(IRComRxQueue));//接收队列初 始化 QQInit(IRCOM_TX_QUEUE_PTR,sizeof(IRComTxQueue));//发送队列初 始化 //IO口配置 GPIO_Init(IR_RX_PORT, (GPIO_InitTypeDef *)&IRComRx); GPIO_Init(IR_TX_PORT, (GPIO_InitTypeDef *)&IRComTx); NVIC_Init((NVIC_InitTypeDef *)&IRComRx_NVIC_InitStruct);//中断向量配置 NVIC_Init((NVIC_InitTypeDef *)&IRComTx_NVIC_InitStruct);//中断向量配置 TIM_InternalClockConfig(IR_TX_TIMER);//设置使用内部时钟 TIM_InternalClockConfig(IR_PWM_TIMER);//设置使用内部时钟 TIM_TimeBaseInit(IR_TX_TIMER, (TIM_TimeBaseInitTypeDef *)&IRTimerBaseCfg ); TIM_TimeBaseInit(IR_PWM_TIMER, (TIM_TimeBaseInitTypeDef *)&IRTimerBaseCfg ); IRComPortSetRxModeCap();//设置为接收捕获模式 } //-------------------------------------------------------------------- u32 IRComPortRead(u8 *pBuf, u32 MaxLen, u32 Timeout) { register u32 i; register u32 Time; register bool Ack; ASSERT(pBuf != NULL); if(MaxLen == 0) return(0); Ack = false; i=0; Time = OSTimeGet(); while(i < MaxLen) { u8 c; if(QQGetChar(IRCOM_RX_QUEUE_PTR,&c))//队列不空,取到数据 { Ack = true; *(pBuf+i) = c; i++; Time = OSTimeGet(); } else//队列空,未取到数 { if(Ack) { if(OSTimeGet() - Time > IRCOM_BYTE_TIMEOUT) break; } else { if((Timeout > 0)&&(OSTimeGet() - Time > Timeout)) break; } OSTimeDly(1); } } return(i); } //-------------------------------------------------------------------- u32 IRComPortWrite(u8 *pBuf, u32 Len, u32 Timeout) { register u32 i; register u32 Time; register bool SendStart; ASSERT(pBuf != NULL); if(Len == 0) return(0); i = 0; SendStart = false; Time = OSTimeGet(); while(i
0)&&((OSTimeGet()-Time)>Timeout)) break; OSTimeDly(1); } } if(!SendStart)//如果未启动发送 { SendStart=true; IRComPortStartupSend();//启动发送 } while(!QQChkEmpty(IRCOM_TX_QUEUE_PTR))//等待发送队列空 { if((Timeout>0)&&((OSTimeGet()-Time)>Timeout)) break; OSTimeDly(1); } OSTimeDly(1);//等待最后一字节发完 return(i); } //-------------------------------------------------------------------- void IRComPortRxIntDeal(void)//接收捕获比较中断处理 { if (TIM_GetITStatus(IR_RX_TIMER, IR_RX_CHNNL) != RESET)//有捕获或比较 中断 { TIM_ClearITPendingBit(IR_RX_TIMER, IR_RX_CHNNL);//清中断标志 if(IRComData.RxComMode == 0)//捕获模式 { IRComPortRxCapToComp();//由捕获模式转换到比较模式 IRComData.RXStep = 0; } else//比较模式 { u8 Status = GPIO_ReadInputDataBit(IR_RX_PORT, IR_RX_PIN); if(IRComData.RXStep == 0)//开始位处理 { if(Status != RESET)//是高电平,开始位错误 { IRComPortSetRxModeCap();//设置到捕获模式 } else//是低电平,开始位正确 { TIM_SetCompare(IR_RX_TIMER, IR_RX_CHNNL, TIM_GetCapture(IR_RX_TIMER, IR_RX_CHNNL)+IRComData.BitTClkNum);//设置比较值 IRComData.RXStep++; IRComData.RXChar = 0; } } else if(IRComData.RXStep <= IRComData.DataBit)//数据位处理 { TIM_SetCompare(IR_RX_TIMER, IR_RX_CHNNL, TIM_GetCapture(IR_RX_TIMER, IR_RX_CHNNL)+IRComData.BitTClkNum);//设置比较值 if(Status != RESET) IRComData.RXChar |= *(BitMask+IRComData.RXStep-1); IRComData.RXStep++; } else if(IRComData.RXStep == IRComData.DataBit+1)//校验或停止位处理 { QQSetChar(IRCOM_RX_QUEUE_PTR, IRComData.RXChar);//放接收数据入接收队列 if(IRComData.Parity != VB_NONE)//有校验位 { bool Parity = CalParity(IRComData.RXChar);//奇数个1返回true if(IRComData.Parity == VB_ODD) { if(Parity == Status)//奇校验错误 IRComData.ParityErr = 1; else IRComData.ParityErr = 0; } else { if(Parity == Status) IRComData.ParityErr = 0; else IRComData.ParityErr = 1; } } IRComPortRxCompToCap();//由接收比较转换到接收捕获模式 } } } } //-------------------------------------------------------------------- void IRComPortTxIntDeal(void) { TIM_ClearITPendingBit(IR_TX_TIMER, IR_TX_CHNNL);//清中断标志 if(IRComData.TXStep == 0) { if(QQGetChar(IRCOM_TX_QUEUE_PTR, &(IRComData.TXChar)))//如果队列不空,取数据成功 { TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum);//设置发送比较值 SetPWMOutput(true);//使能PWM 输出 IRComData.TXStep++; } else//队列空,数据发送结束 { IRComPortSetRxModeCap();//设置到接收捕获模式 } } else if(IRComData.TXStep <= IRComData.DataBit)//处理数据位 { TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum);//设置发送比较值 if((IRComData.TXChar & (*(BitMask + IRComData.TXStep -1))) == RESET) SetPWMOutput(true);//使能PWM 输出 else SetPWMOutput(false);//禁能PWM 输出 IRComData.TXStep++; } else if(IRComData.TXStep == IRComData.DataBit+1)//处理数据位后一位 { if(IRComData.Parity == VB_NONE)//无校验位,则发送停止位 { TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum/2*(IRComData.StopBit+1));//设置发送比较值 SetPWMOutput(false);//禁能PWM 输出 IRComData.TXStep = 0; } else { bool Parity; TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum);//设置发送比较值 Parity = CalParity(IRComData.TXChar);//奇数个1返回true if(IRComData.Parity == VB_ODD)//奇校验 { if(Parity)//是奇数个1 SetPWMOutput(true);//使能PWM 输出 else SetPWMOutput(false);//禁能PWM 输出 } else if(IRComData.Parity == VB_EVEN) { if(Parity)//是奇数个1 SetPWMOutput(false);//禁能PWM 输出 else SetPWMOutput(true);//使能PWM 输出 } IRComData.TXStep++; } } else if(IRComData.TXStep == IRComData.DataBit + 2)//处理停止位 { TIM_SetCompare(IR_TX_TIMER, IR_TX_CHNNL, TIM_GetCapture(IR_TX_TIMER, IR_TX_CHNNL)+IRComData.BitTClkNum/2*(IRComData.StopBit+1));//设置发送比较值 SetPWMOutput(false);//禁能PWM 输出 IRComData.TXStep = 0; } } //-------------------------------------------------------------------- #ifdef DEBUG #include "Com1Port.h" void IRComPortTest(void) { Com1PortInit(1200, VB_EVEN, SB_1); IRComPortInit(1200, VB_EVEN, SB_1); while(1) { u8 Buf[128]; u32 Len; Len = Com1PortRead(Buf, sizeof(Buf), OS_TICKS_PER_SEC/2); if(Len > 0) { IRComPortWrite(Buf,Len,OS_TICKS_PER_SEC*2); Len = IRComPortRead(Buf,sizeof(Buf),OS_TICKS_PER_SEC*2); if(Len > 0) Com1PortWrite(Buf, Len, OS_TICKS_PER_SEC*2); } } } #endif //-------------------------------------------------------------------- ```
2
个回答
默认排序
按发布时间排序
jizhongbiao
2022-12-20
这家伙很懒,什么也没写!
设置定时器和外部中断的优先级变高,然后设置rtthread管理的优先级下限。确保不要让定时器和外部中断的优先级被系统关掉。
撰写答案
登录
注册新账号
关注者
1
被浏览
1.9k
关于作者
zx595
这家伙很懒,什么也没写!
提问
9
回答
12
被采纳
0
关注TA
发私信
相关问题
1
在树莓派3b上用GPIO模拟串口
2
线程为什么会影响IO模拟串口的接收
3
哪里有适合初学者的资料吗?
4
关于raspberry pico通过usbcdc来实现串口功能的问题
5
求教关于rt_tick_increase函数导致外部中断响应延迟的问题与解决思路
6
系统在什么时候开启中断
7
在系统初始化之前一定要关中断吗,如果中断开启,系统会紊乱吗?
8
rt-thread 定时器 HARD_TIMER 模式 中断
9
Rt-thread的系统中断在哪里开启
10
bug反馈:中断号有问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
a1012112796
13
个答案
1
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
6
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部