历史上的今天
返回首页

历史上的今天

今天是:2025年04月09日(星期三)

正在发生

2019年04月09日 | STM32串口环形缓冲区

2019-04-09 来源:eefocus

1:概述


1.1:本篇实现串口驱动,实现printf函数的重定向,实现串口的中断接受和发送,效仿modbus协议中的3.5T超时机制,判断是否接受完毕;


1.2:如果串口仅仅是实现一个控制台,打印一些debug数据,使用printf函数(串口发送数据忙等待),如果是需要用串口进行外设设备的控制,比如串口GPRS模块,需使用串口中断进行控制,因为受限于串口的传输速率,如果使用忙等待发送数据,会阻塞主程序中的其它任务;


1.3:使用sysclk作为超时定时器,sysclk的中断优先级需高于串口中断;


1.4:除过使用3.5T超时时间判断接受数据是否完成外,还可使用ASCLL码的形式,利用字符操作库函数,自定义串口通信协议;


1.5:开发板:stm32f103zert   软件环境:KEIL MKD5


1.6:115200 波特率,间隔1ms发送字符串 "PassWord",主程序将接收到"PassWord"后返回"123456rn",测试主程序响应迅速,不丢帧;


2:代码


main.c



#include "stm32f10x.h"

#include "usart_init.h"

#include "timer.h"

#include "Sys_Driver.h"

 

unsigned int baud[5] = {9600,14400,19200,56000,115200};

unsigned int T_35 = 0;     //串口发送3.5个字节的时间,由波特率得出,单位为ms

 

int main(void)

{

T_35 = 3.5*(10000000/baud[4]);     

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);     //设置中断优先级分组

Usart_Init(baud[4]);  //串口初始化 

SysTick_Init(INT_1US,SysTick_CLKSource_HCLK_Div8);  //sysclk初始化,设置1ms中断

timer_set(&usart_timer,T_35);   //定义一个串口计时器 



while(1)

{

if(Start_Receive_Flag == 1)

{

if(timer_expired(&usart_timer) == 1)   //3.5T时间到达,一条串口数据接受成功

{

Start_Receive_Flag = 0;

Usart_Handle_Func();

}

}

}

}


usart_init.c



#include "usart_init.h"

 

 

u8 Usart_Receive_Ok = 0;

u8 Start_Receive_Flag = 0;

 

u8 Usart_TX_Buff[TX_RE_BUFF_LENGTH];

u8 Usart_RX_Buff[TX_RE_BUFF_LENGTH];

COMx_Define CYCLE;

 

 

/*******************printf()函数重定向***************/

//发送函数

int fputc(int ch, FILE *f)

{

USART_SendData(USART2, (unsigned char) ch);

while (!(USART2->SR & USART_FLAG_TXE));

return (ch);

}

 

//接受函数

int fgetc(FILE *f)  

{

while (!(USART2->SR & USART_FLAG_RXNE));

return USART_ReceiveData(USART2);

}

 

 

void Usart_Init(u32 baud)

{

GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

 

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   //使能USART2,GPIOA时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //使能USART2,GPIOA时钟


//USART2_TX   PA.2

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; 

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_Init(GPIOA, &GPIO_InitStructure); 

   

  //USART2_RX   PA.3

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA, &GPIO_InitStructure); 

 

  //USART2 NVIC 配置

  NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;    //抢占优先级2

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;      //子优先级2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        //IRQ通道使能

NVIC_Init(&NVIC_InitStructure);                            //根据指定的参数初始化VIC寄存器

  

  //USART 初始化设置

USART_InitStructure.USART_BaudRate = baud;        

USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式

USART_InitStructure.USART_StopBits = USART_StopBits_1;     //一个停止位

USART_InitStructure.USART_Parity = USART_Parity_No;        //无奇偶校验位

USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //无硬件数据流控制

USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;                  //收发模式

 

USART_Init(USART2, &USART_InitStructure);                   //初始化串口

USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);  //开启发送完成中断和接收完成中断  

USART_ITConfig(USART2,USART_IT_TC,ENABLE);  //开启发送完成中断和接收完成中断

USART_Cmd(USART2, ENABLE);                                  //使能串口 

}

 

void Usart_Send_Byte(u8 data)

{

Usart_TX_Buff[CYCLE.TX_write] = data;      //装发送缓冲区

if(++CYCLE.TX_write == TX_RE_BUFF_LENGTH)

CYCLE.TX_write = 0;


if(CYCLE.TX_busy == 0)                     //发送空闲

{

CYCLE.TX_busy = 1;

USART_SendData(USART2,Usart_TX_Buff[CYCLE.TX_read]);  //想串口发送数据,触发中断

if(++CYCLE.TX_read == TX_RE_BUFF_LENGTH)

CYCLE.TX_read = 0;

}

}

 

/*串口发送函数*/

void Usart_Send_Data(u8 *ptr,u8 num)

{

if(num == 0)                                   //发送字符串

{

for(;*ptr!='';ptr++)

{

Usart_Send_Byte(*ptr);

}

}

else                                           //发送num字节数据

{

for(;num>0;num--)

{

Usart_Send_Byte(*ptr++);

}

}

}

 

/*串口接收函数,当接收到可用的数据帧时,对接收到的数据进行处理,main函数中调用*/

void Usart_Handle_Func(void)

{

u8 i = 0;

u8 Buff[40];

while(CYCLE.RX_read != CYCLE.RX_write)

{

Buff[i++] = Usart_RX_Buff[CYCLE.RX_read];

if(++CYCLE.RX_read == TX_RE_BUFF_LENGTH)

CYCLE.RX_read = 0;

}

Buff[i] = '';

// Usart_Send_Data(Buff,0);

// Usart_Send_Data("rn",0);

if(memcmp(Buff,"PassWord",8) == 0)

{

Usart_Send_Data("123456rn",0);

}

}

 

///*中断处理函数*/

void USART2_IRQHandler(void)

{

u8 data;

if(USART_GetITStatus(USART2,USART_IT_TC) == SET)    //发送完成中断

{

USART_ClearITPendingBit(USART2,USART_IT_TC);

if(CYCLE.TX_read != CYCLE.TX_write)

{

USART_SendData(USART2,Usart_TX_Buff[CYCLE.TX_read]);

if(++CYCLE.TX_read == TX_RE_BUFF_LENGTH)

CYCLE.TX_read = 0;

}

else

{

CYCLE.TX_busy = 0;                                 //缓冲区数据发送完成,串口总线空闲,可以开始发送新的数据

}

}

else

if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)  //接收完成中断

{

USART_ClearITPendingBit(USART2,USART_IT_RXNE);

data = USART_ReceiveData(USART2);

Usart_RX_Buff[CYCLE.RX_write] = data;

if(++CYCLE.RX_write == TX_RE_BUFF_LENGTH)

CYCLE.RX_write = 0;

timer_reset(&usart_timer);   //开始计时

Start_Receive_Flag = 1;

}

}

推荐阅读

史海拾趣

FTDI [Future Technology Devices International Ltd.]公司的发展小趣事

随着市场需求的变化,FTDI并未满足于初期的成就,而是积极拓展产品线。他们推出了如MM232R和USB-COM232-PLUS1等接口产品,这些产品在连接性和兼容性上展现了公司强大的技术实力和创新精神。同时,FTDI还涉足USB和其他通信协议的转换领域,满足了多样化的市场需求,进一步巩固了其在电子行业中的地位。

Aerovox Corporation公司的发展小趣事

近年来,FTDI通过并购等方式不断拓展其业务范围。例如,电连技术通过发行股份及支付现金的方式收购了FTDI的部分股权,使FTDI成为其控股子公司。这一并购不仅为电连技术带来了FTDI在USB桥接芯片领域的领先技术,还促进了双方在产品、客户和销售渠道等方面的协同效应。同时,FTDI也借此机会进一步提升了其在新兴市场如汽车电子、物联网等领域的竞争力。

CLARE公司的发展小趣事

为了进一步拓展市场,CLARE公司积极开拓国内市场,并与多家知名企业建立了战略合作关系。同时,公司还积极进军国际市场,通过参加国际展会、设立海外分支机构等方式,加强与国际客户的交流与合作。这些举措不仅为CLARE公司带来了更多的商业机会,也进一步提升了其在全球电子行业中的地位和影响力。

GD Rectifiers Ltd公司的发展小趣事

为了进一步扩大市场份额,GD Rectifiers Ltd实施了积极的国际化战略。公司首先在欧洲市场设立了销售分支机构,凭借其优质的产品和服务迅速赢得了当地客户的认可。随后,公司又陆续在北美、亚洲等地区建立了分销网络,逐步构建起覆盖全球的营销体系。在国际化进程中,GD Rectifiers Ltd注重与当地企业的合作与交流,共同推动行业标准的制定和技术进步。通过不断的努力,公司成功地将品牌和产品推向了全球市场,实现了业务规模的快速增长。

永源微电子(APM)公司的发展小趣事

随着国内外市场的不断开拓和技术实力的不断提升,永源微电子开始实施全球化战略。公司积极寻求与国际知名企业的合作机会,通过技术引进和合资合作等方式,不断提升自身的国际化水平。同时,永源微电子还注重内部管理和人才培养,通过建立完善的管理体系和激励机制,吸引和留住了一批优秀的技术人才和管理人才。在全球化战略的推动下,永源微电子实现了持续稳健的发展,成为了电子行业中一颗璀璨的明星。

以上五个故事分别从不同角度描绘了永源微电子(APM)公司的发展历程,包括创立与初步发展、技术突破与产品线拓展、市场拓展与品牌建设、A轮融资与战略合作以及全球化战略与持续发展等方面。这些故事基于事实性的描述,展现了永源微电子在电子行业中的成长轨迹和发展成就。

康龙(CONCRAFT)公司的发展小趣事

作为一家有社会责任感的企业,康龙公司始终关注环境保护和可持续发展。公司积极采用环保材料和生产工艺,减少生产过程中的污染和浪费。同时,康龙还积极参与社会公益事业和慈善活动,回馈社会。这些举措不仅提升了公司的品牌形象和社会声誉,也为公司的长远发展注入了正能量。

问答坊 | AI 解惑

2008年新出版的<嵌入式硬件>,抢先分享

刚从国外拿到的.供大家分享!!!!…

查看全部问答>

PADS2007有中文版的吗

那位大哥能告诉我PADS2007有中文版的吗,那里有中文版的下载?…

查看全部问答>

关于单片发at指令

请教各位高手,单片机是如何向gprs模块发送at指令的,我如何调试呢?…

查看全部问答>

造型请教:有没有可以查询FPGA/CPLD芯片的价格查询网址?

现在在选型FPGA,要用到161个IO,编数组功能单元。 公司没有BGA焊接设备,只能焊引脚能看到的封装 打算用Virtex的,两个TQ144封装的(IO=2*98),或者一个PQ240的(IO=166) 不知道这几种贵不贵,考虑成本,想用几百元的! …

查看全部问答>

ADO如何连接sqlce????

请教各位达人一下: 我是在visual studio 2005下建立的vc++ MFC智能设备应用程序,想通过ADO访问智能设备本地sdf数据库中的数据表,请问可以实现吗???如果可以,麻烦请给个连接字符串,还要包含什么文件????谢谢…

查看全部问答>

我做的触摸屏显示的坐标总是4095,应该触摸不同的位置变化的,为什么?

我做的触摸屏显示的坐标总是4095,应该触摸不同的位置变化的,为什么?…

查看全部问答>

vxworks 广播数据包

控创的单扳机,扩展为双网卡(fei0,eeE0) eeE0:192.168.1.100:0xffffff00  udp协议组网 网上其他设备向某一端口 广播数据 广播地址:192.168.1.255 正确创建socket 后,接收不到广播数据包. 如果同一端口不广播,而是点对点则能正确收 ...…

查看全部问答>

TI Sitara入门资料分享9-AM335X数据手册-部分汉化

去TI下资料是个很复杂的过程,特别是最近城墙加高,google抽筋的河蟹时段,好不容易找到 一份AM335X数据手册,还是部分汉化的,不敢独享 这里下载: [ 本帖最后由 shower.xu 于 2012-11-2 15:58 编辑 ]…

查看全部问答>