1
完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
2个回答
|
|
前言:最近芯片涨价还缺货,寻找替换方案是目前的解决办法,对于串口不够用的时候,可以考虑软件模拟方案。
一 原理讲解 明白模拟串口怎么实现。用到的外设有普通gpio,外部中断,定时器。 本程序的代码在: 1.2 发送 串口发送每一个字节时候,每一个比特位占用多少时间, 如:波特率是38400,
注意:这里要说明一下,HALL库的延时函数是在systick中断里面每ms加1s,没有延时的时候中断没有关闭,导致系统资源浪费。 正确的应该是给定时器1计数设置一个初始值,硬件自动加数,在delay里面读计数值,比如L431系统时钟是80MHz,定时器的配置如下: 定时器1每加1,时间是1us,我要延时26us,那我就再delay里面一直读定时器的CNT寄存器值是不是大于26。 1.3 接收 接收数据的时候,下降沿激发产生外部中断事件,开启定时器2。每隔一段时间读取一下gpio引脚的电平状态,保存在临时数组,到停止位则一个字节数据接收完成,读取字节数据,放在全局256大小的缓冲区。 注意:这里读取GPIo引脚的状态,应该在每个bit位的1/2读取GPIO的状态,这样读取的数据比较准确。 1.4 数据分包 有没有考虑过一个问题,怎么样收一包数据? 这里有个数据分包的问题,数据分包是这样的,我在数据停止位拿到数据以后,吧定时器2中断时间延长,我定义了两包数据之间的间隔大于100us,这里有两种情况:
2.1 GPIO配置 2.2 定时器2中断,外部中断 2.3 定时器1配置 2.4 定时器2配置 配置好后生成工程 三 代码 3.1 修改tim.c 实现定时器初始化,delay_ms(),delay_us(),定时器2回调 /* Includes ------------------------------------------------------------------*/ #include "tim.h" /* USER CODE BEGIN 0 */ #include "myusart_RX.h" /* USER CODE END 0 */ TIM_HandleTypeDef htim1; TIM_HandleTypeDef htim2; /* TIM1 init function */ void MX_TIM1_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; htim1.Instance = TIM1; htim1.Init.Prescaler = 80-1; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 1; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim1.Init.RepetitionCounter = 0; htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim1) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK) { Error_Handler(); } } /* TIM2 init function */ void MX_TIM2_Init(void) { TIM_ClockConfigTypeDef sClockSourceConfig = {0}; TIM_MasterConfigTypeDef sMasterConfig = {0}; htim2.Instance = TIM2; htim2.Init.Prescaler = 8-1; htim2.Init.CounterMode = TIM_COUNTERMODE_DOWN; htim2.Init.Period = 130; htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE; if (HAL_TIM_Base_Init(&htim2) != HAL_OK) { Error_Handler(); } sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK) { Error_Handler(); } sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK) { Error_Handler(); } } void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM1) { /* USER CODE BEGIN TIM1_MspInit 0 */ /* USER CODE END TIM1_MspInit 0 */ /* TIM1 clock enable */ __HAL_RCC_TIM1_CLK_ENABLE(); /* USER CODE BEGIN TIM1_MspInit 1 */ /* USER CODE END TIM1_MspInit 1 */ } else if(tim_baseHandle->Instance==TIM2) { /* USER CODE BEGIN TIM2_MspInit 0 */ /* USER CODE END TIM2_MspInit 0 */ /* TIM2 clock enable */ __HAL_RCC_TIM2_CLK_ENABLE(); /* TIM2 interrupt Init */ HAL_NVIC_SetPriority(TIM2_IRQn, 0, 0); HAL_NVIC_EnableIRQ(TIM2_IRQn); /* USER CODE BEGIN TIM2_MspInit 1 */ /* USER CODE END TIM2_MspInit 1 */ } } void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance==TIM1) { /* USER CODE BEGIN TIM1_MspDeInit 0 */ /* USER CODE END TIM1_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM1_CLK_DISABLE(); /* USER CODE BEGIN TIM1_MspDeInit 1 */ /* USER CODE END TIM1_MspDeInit 1 */ } else if(tim_baseHandle->Instance==TIM2) { /* USER CODE BEGIN TIM2_MspDeInit 0 */ /* USER CODE END TIM2_MspDeInit 0 */ /* Peripheral clock disable */ __HAL_RCC_TIM2_CLK_DISABLE(); /* TIM2 interrupt Deinit */ HAL_NVIC_DisableIRQ(TIM2_IRQn); /* USER CODE BEGIN TIM2_MspDeInit 1 */ /* USER CODE END TIM2_MspDeInit 1 */ } } 下面是自己加的 /* USER CODE BEGIN 1 */ //实现微妙延时功能 void delay_us(uint16_t us) { uint16_t differ=0xffff-us-5; HAL_TIM_Base_Start(&htim1);//打开定时器 __HAL_TIM_SetCounter(&htim1,differ);//设置计数初始值 while(differ < 0xffff-5) { differ = __HAL_TIM_GetCounter(&htim1);//拿到计数值 } HAL_TIM_Base_Stop(&htim1);//关闭定时器 } void delay_ms(uint16_t ms) { for(uint16_t i=0;i delay_us(1000); } } void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef* tim_baseHandle) { if(tim_baseHandle->Instance == htim2.Instance) { TIM2_IRQHandlerHandle(); } } /* USER CODE END 1 */ 3.2 修改gpio.c 实现引脚初始化,外部中断回调 #include "gpio.h" /* USER CODE BEGIN 0 */ #include "myusart_RX.h" /* USER CODE END 0 */ /*----------------------------------------------------------------------------*/ /* Configure GPIO */ /*----------------------------------------------------------------------------*/ /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /** Configure pins */ void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(usart_tx_GPIO_Port, usart_tx_Pin, GPIO_PIN_SET); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = usart_tx_Pin; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(usart_tx_GPIO_Port, &GPIO_InitStruct); /*Configure GPIO pin : PtPin */ GPIO_InitStruct.Pin = usart_rx_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(usart_rx_GPIO_Port, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI15_10_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); } 下面是自己加的 /* USER CODE BEGIN 2 */ /** * @brief EXIT中断回调函数 * @param GPIO_Pin —— 触发中断的引脚 * @retval none */ void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { /* 判断哪个引脚触发了中断 */ switch(GPIO_Pin) { case usart_rx_Pin: GPIO_A_10_CALLBACK(); break; case GPIO_PIN_3: break; default: break; } } /* USER CODE END 2 */ 3.3 增加myusart_TX.c 实现发射功能 #include "myusart_TX.h" #include "gpio.h" #include "core_cm4.h" #include "tim.h" #define BuadRate_9600 100 #define BuadRate_38400 26 void delay_tx(void)//26.04us { delay_us(BuadRate_38400-1); //补偿 __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); __NOP(); } void IO_TXD(uint8_t Data) { uint8_t i = 0; HAL_GPIO_WritePin(usart_tx_GPIO_Port, usart_tx_Pin, GPIO_PIN_RESET); delay_tx(); for(i = 0; i < 8; i++) { if(Data&0x01) HAL_GPIO_WritePin(usart_tx_GPIO_Port, usart_tx_Pin, GPIO_PIN_SET); else HAL_GPIO_WritePin(usart_tx_GPIO_Port, usart_tx_Pin, GPIO_PIN_RESET); delay_tx(); Data = Data>>1; } HAL_GPIO_WritePin(usart_tx_GPIO_Port, usart_tx_Pin, GPIO_PIN_SET); delay_tx(); } //定义的发送函数 void USART_Send(uint8_t *buf, uint8_t len) { uint8_t t; for(t = 0; t < len; t++) { IO_TXD(buf[t]); } } char *p="okokokokok"; void test_TX() { USART_Send((uint8_t *)p,10); delay_ms(500); } 3.4 增加myusart_TX.h #ifndef __myusart_TX_H__ #define __myusart_TX_H__ #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include "main.h" void test_TX(void); void USART_Send(uint8_t *buf, uint8_t len); #ifdef __cplusplus } #endif #endif /*__ GPIO_H__ */ 3.5 增加myusart_RX.c #include "myusart_RX.h" #include "myusart_TX.h" #include "gpio.h" #include "core_cm4.h" #include "tim.h" #define BuadRate_9600 100 #define BuadRate_38400 26 #define UsartPack_delay 1000//100us uint8_t len = 0; //接收了多少个字节 uint8_t USART_buf[256]; //接收缓冲区 uint8_t DateReceiveIsOK=0;//接收到数据标志 uint8_t len8buf = 0; uint8_t USART_8buf[20]; enum{ COM_START_BIT_NOP, COM_START_BIT, COM_D0_BIT_NOP, COM_D0_BIT, COM_D1_BIT_NOP, COM_D1_BIT, COM_D2_BIT_NOP, COM_D2_BIT, COM_D3_BIT_NOP, COM_D3_BIT, COM_D4_BIT_NOP, COM_D4_BIT, COM_D5_BIT_NOP, COM_D5_BIT, COM_D6_BIT_NOP, COM_D6_BIT, COM_D7_BIT_NOP, COM_D7_BIT, COM_STOP_BIT, COM_pack_delay, }; uint8_t recvStat = COM_STOP_BIT; uint8_t recvData = 0; /********************************TX*********************************/ void TIM2_IRQHandlerHandle(void) { recvStat++; if(HAL_GPIO_ReadPin(usart_rx_GPIO_Port,usart_rx_Pin)) { USART_8buf[len8buf++]=1; }else{ USART_8buf[len8buf++]=0; } if(recvStat == COM_STOP_BIT) { // for(uint8_t i=1;i<9;i++ ) { if(USART_8buf[2*i])//2 4 6 8 10 12 14 16 { recvData |= (1 << (i - 1)); }else{ recvData &= ~(1 << (i - 1)); } } USART_buf[len++] = recvData; //收到一个字节,吧定时器的中断 延长到UsartPack_delay us __HAL_TIM_SetCounter(&htim2, 10*UsartPack_delay); __HAL_TIM_SET_AUTORELOAD(&htim2, 10*UsartPack_delay); return; }else if(recvStat >= COM_pack_delay)//分包处理 { //关闭定时器中断 HAL_TIM_Base_Stop_IT(&htim2); //吧定时器时间调整到原来的13us __HAL_TIM_SET_AUTORELOAD(&htim2, 10* BuadRate_38400/2);//定时器13us来一次中断 __HAL_TIM_SetCounter(&htim2, 10* BuadRate_38400/2);//定时器计数初始值130 //关闭定时器 __HAL_RCC_TIM2_CLK_DISABLE(); DateReceiveIsOK=1; return; } } void GPIO_A_10_CALLBACK(void) { if(HAL_GPIO_ReadPin(usart_rx_GPIO_Port,usart_rx_Pin) == 0) //判断是低电平 { if((recvStat == COM_STOP_BIT)||(recvStat == COM_pack_delay)) { //变量清0 recvStat = COM_START_BIT_NOP; len8buf=0; //启动定时器 __HAL_TIM_SET_AUTORELOAD(&htim2, 10*BuadRate_38400/2);//定时器计数初始值130 __HAL_TIM_SetCounter(&htim2, 10* BuadRate_38400/2);//定时器13us来一次中断 __HAL_RCC_TIM2_CLK_ENABLE(); HAL_TIM_Base_Start_IT(&htim2); } } } /*******************************************************************************/ void test_rx() { if(DateReceiveIsOK == 1) { USART_Send(USART_buf,len); len = 0; DateReceiveIsOK=0; } } |
|
|
|
3.6 增加myusart_RX.h
#ifndef __myusart_RX_H__ #define __myusart_RX_H__ #ifdef __cplusplus extern "C" { #endif /* Includes ------------------------------------------------------------------*/ #include "main.h" void test_rx(void); void GPIO_A_10_CALLBACK(void); void TIM2_IRQHandlerHandle(void); #ifdef __cplusplus } #endif #endif /*__ GPIO_H__ */ 3.7 main.c /* USER CODE BEGIN Includes */ #include "myusart_RX.h" #include "myusart_TX.h" /* USER CODE END Includes */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ // test_TX(); test_rx(); } |
|
|
|
只有小组成员才能发言,加入小组>>
3323 浏览 9 评论
3000 浏览 16 评论
3498 浏览 1 评论
9073 浏览 16 评论
4093 浏览 18 评论
1194浏览 3评论
614浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
603浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2343浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1902浏览 2评论
小黑屋| 手机版| Archiver| 德赢Vwin官网 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-30 21:39 , Processed in 1.041656 second(s), Total 50, Slave 41 queries .
Powered by 德赢Vwin官网 网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
德赢Vwin官网 观察
版权所有 © 湖南华秋数字科技有限公司
德赢Vwin官网 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号