STM32串口协议

目前我总结了两种串口通信时用到的串口协议程序。均学习的原子哥的。

一、定义某个字符为一次接收数据完成,如/n/r。

二、定义两个字符接收时间间隔,如10ms。超过即为第二次接收。

一、程序示意:


二、程序示意、


#include \"delay.h\"
#include \"usart2.h\"
#include \"stdarg.h\"        
#include \"stdio.h\"         
#include \"string.h\"      
//   
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//串口2驱动代码      
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2013/2/22
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved                                     
//     
 
//串口发送缓存区   
__align(8) u8 USART2_TX_BUF[USART2_MAX_SEND_LEN];   //发送缓冲,最大USART2_MAX_SEND_LEN字节
#ifdef USART2_RX_EN                                 //如果使能了接收         
//串口接收缓存区   
u8 USART2_RX_BUF[USART2_MAX_RECV_LEN];              //接收缓冲,最大USART2_MAX_RECV_LEN个字节.
 
 
//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
u16 USART2_RX_STA=0;     
void USART2_IRQHandler(void)
{
    u8 res;     
    if(USART2->SR&(1<<5))//接收到数据
    {    
        res=USART2->DR;           
        if(USART2_RX_STA<USART2_MAX_RECV_LEN)        //还可以接收数据
        {
            TIM4->CNT=0;                             //计数器清空
            if(USART2_RX_STA==0)TIM4_Set(1);        //使能定时器4的中断 
            USART2_RX_BUF[USART2_RX_STA++]=res;     //记录接收到的值    
        }else
        {
            USART2_RX_STA|=1<<15;                 //强制标记接收完成
        } 
    }                                            
}   
//初始化IO 串口2
//pclk1:PCLK1时钟频率(Mhz)
//bound:波特率   
void USART2_Init(u32 pclk1,u32 bound)
{            
    RCC->APB2ENR|=1<<8;    //使能PORTG口时钟  
    GPIOG->CRH&=0XFFFFFF0F;  //IO状态设置
    GPIOG->CRH|=0X00000030;  //IO状态设置
    RCC->APB2ENR|=1<<2;    //使能PORTA口时钟  
    GPIOA->CRL&=0XFFFF00FF;  //IO状态设置
    GPIOA->CRL|=0X00008B00;  //IO状态设置     
    RCC->APB1ENR|=1<<17;   //使能串口时钟     
    RCC->APB1RSTR|=1<<17;   //复位串口2
    RCC->APB1RSTR&=~(1<<17);//停止复位        
    //波特率设置
    USART2->BRR=(pclk1*1000000)/(bound);// 波特率设置  
    USART2->CR1|=0X200C;     //1位停止,无校验位.
    USART2->CR3=1<<7;      //使能串口2的DMA发送
    UART_DMA_Config(DMA1_Channel7,(u32)&USART2->DR,(u32)USART2_TX_BUF);//DMA1通道7,外设为串口2,存储器为USART2_TX_BUF 
#ifdef USART2_RX_EN         //如果使能了接收
    //使能接收中断
    USART2->CR1|=1<<8;     //PE中断使能
    USART2->CR1|=1<<5;     //接收缓冲区非空中断使能           
    MY_NVIC_Init(2,3,USART2_IRQn,2);//组2,最低优先级 
    TIM4_Init(99,7199);     //10ms中断
    USART2_RX_STA=0;        //清零
    TIM4_Set(0);            //关闭定时器4
#endif                                          
}
//串口2,printf 函数
//确保一次发送数据不超过USART2_MAX_SEND_LEN字节
void u2_printf(char* fmt,...)  
{  
    va_list ap;
    va_start(ap,fmt);
    vsprintf((char*)USART2_TX_BUF,fmt,ap);
    va_end(ap);
    while(DMA1_Channel7->CNDTR!=0);  //等待通道7传输完成   
    UART_DMA_Enable(DMA1_Channel7,strlen((const char*)USART2_TX_BUF));  //通过dma发送出去
}
//定时器4中断服务程序            
void TIM4_IRQHandler(void)
{   
    if(TIM4->SR&0X01)//是更新中断
    {                  
        USART2_RX_STA|=1<<15; //标记接收完成
        TIM4->SR&=~(1<<0);     //清除中断标志位          
        TIM4_Set(0);            //关闭TIM4  
    }       
}
//设置TIM4的开关
//sta:0,关闭;1,开启;
void TIM4_Set(u8 sta)
{
    if(sta)
    {
        TIM4->CNT=0;         //计数器清空
        TIM4->CR1|=1<<0;     //使能定时器4
    }else TIM4->CR1&=~(1<<0);//关闭定时器4     
}
//通用定时器中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数         
void TIM4_Init(u16 arr,u16 psc)
{
    RCC->APB1ENR|=1<<2;    //TIM4时钟使能    
    TIM4->ARR=arr;   //设定计数器自动重装值   
    TIM4->PSC=psc;   //预分频器
    TIM4->DIER|=1<<0;   //允许更新中断               
    TIM4->CR1|=0x01;     //使能定时器4           
    MY_NVIC_Init(1,3,TIM4_IRQn,2);//抢占2,子优先级3,组2    在2中优先级最低                                 
}
#endif       
///USART2 DMA发送配置部分//               
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx
//cpar:外设地址
//cmar:存储器地址    
void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar)
{
    RCC->AHBENR|=1<<0;         //开启DMA1时钟
    delay_us(5);
    DMA_CHx->CPAR=cpar;      //DMA1 外设地址 
    DMA_CHx->CMAR=cmar;      //DMA1,存储器地址     
    DMA_CHx->CCR=0X00000000; //复位
    DMA_CHx->CCR|=1<<4;        //从存储器读
    DMA_CHx->CCR|=0<<5;        //普通模式
    DMA_CHx->CCR|=0<<6;        //外设地址非增量模式
    DMA_CHx->CCR|=1<<7;        //存储器增量模式
    DMA_CHx->CCR|=0<<8;        //外设数据宽度为8位
    DMA_CHx->CCR|=0<<10;       //存储器数据宽度8位
    DMA_CHx->CCR|=1<<12;       //中等优先级
    DMA_CHx->CCR|=0<<14;       //非存储器到存储器模式            
} 
//开启一次DMA传输
void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len)
{
    DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输 
    DMA_CHx->CNDTR=len;          //DMA1,传输数据量 
    DMA_CHx->CCR|=1<<0;          //开启DMA传输
}      
/                                    

                             
                     

以下是一个简单的STM32串口通信的代码示例,使用了HAL库: ```c #include "stm32f4xx_hal.h" #include <string.h> UART_HandleTypeDef huart2; void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART2_UART_Init(void); void send_string(UART_HandleTypeDef *huart, char *str); int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART2_UART_Init(); char rx_buffer[10]; char tx_buffer[10]; uint8_t flag = 0; while (1) { HAL_UART_Receive(&huart2, (uint8_t *)rx_buffer, 10, 1000); if (strcmp(rx_buffer, "hello") == 0) { strcpy(tx_buffer, "world"); flag = 1; } if (flag) { send_string(&huart2, tx_buffer); flag = 0; } } } void send_string(UART_HandleTypeDef *huart, char *str) { HAL_UART_Transmit(huart, (uint8_t *)str, strlen(str), 1000); } void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Configure the main internal regulator output voltage */ __HAL_RCC_PWR_CLK_ENABLE(); __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } static void MX_USART2_UART_Init(void) { huart2.Instance = USART2; huart2.Init.BaudRate = 115200; huart2.Init.WordLength = UART_WORDLENGTH_8B; huart2.Init.StopBits = UART_STOPBITS_1; huart2.Init.Parity = UART_PARITY_NONE; huart2.Init.Mode = UART_MODE_TX_RX; huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE; huart2.Init.OverSampling = UART_OVERSAMPLING_16; if (HAL_UART_Init(&huart2) != HAL_OK) { Error_Handler(); } } static void MX_GPIO_Init(void) { __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_2 | GPIO_PIN_3; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } ``` 该示例代码中,通过串口接收数据并判断是否为字符串 "hello",如果是,则发送字符串 "world"。发送数据使用了自定义的 send_string 函数,可以通过修改该函数来实现发送不同格式的数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值