1 前言

STM32有强大的固件库,绝大部分函数都可以有库里面的函数组合编写。固件库可以到ST官网(www.st.com)上下载,也可以搜索“STM32 固件库 v3.5”下载到固件库。本文章就是基于固件库来编写有关串口的输入输出函数。由于博主的知识水平有限,目前仅仅是将程序的思路和实现给出,具体到函数的执行效率、代码的简化方面未进行深入探讨。如果有兴趣的同学可以联系我,我们可以一起探讨一下。

2 STM32固件库

有关固件库的详细介绍,在emouse 思·睿 技术博客里有较为详细的解释(详见http://www.cnblogs.com/emouse/archive/2011/11/29/2268441.html),在本文中就不再讨论。这里仅仅将使用到的库函数列举出来,并不作深入的分析。

2.1 stm32f10x_rcc.c

该文件位于“...\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src”文件夹中。一般调用该文件的函数有:

  • void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)
  • void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
  • void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)

注意:不同的时钟所处的总线是不一样的,最常见的就是USART1和USART2分别位于APB2和APB1中,故写程序时必须分开写。具体函数的参数可以参考“stm32f10x_rcc.c”。

举例:

1   /* Enable GPIOA, GPIOD and USART1 clocks */
2 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD |
3 RCC_APB2Periph_USART1 , ENABLE);
4
5 /* Enable USART2 clocks */
6 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

图1 互联型的系统结构

2.2 stm32f10x_gpio.c

该文件位于“...\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src”文件夹中。一般调用该文件的函数有:

  • void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)

在调用该函数前,通常需要先声明并配置好结构体GPIO_InitTypeDef。该结构体具体定义在stm32f10x_gpio.h(文件位于“...\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\inc”)文件中,需要配置的一般有GPIO_Pin(引脚)、GPIO_Speed(速率)和GPIO_Mode(模式)。

举例:

1   GPIO_InitTypeDef         GPIO_InitStructure;
2
3 /* Configure PA.09 as alternate function push-pull */
4 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
5 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
6 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
7 GPIO_Init(GPIOA, &GPIO_InitStructure);

2.3 misc.c

该文件位于“...\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src”文件夹中。一般调用该文件的函数有:

  • void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
  • void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)

对于中断函数来说,最关键的莫过于优先级排序。函数NVIC_PriorityGroupConfig提供了非常丰富的优先级排序,并通过结构体NVIC_InitTypeDef(位于misc.h文件中)的配置可以完成不同优先级的设置。同样,在使用函数NVIC_Init前,需要配置相应的NVIC_InitTypeDef结构体。

举例:

 1   NVIC_InitTypeDef         NVIC_InitStructure;
2
3 /* Configure two bit for preemptive priority */
4 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
5
6 /* Enable DMA Channel6 Interrupt */
7 NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
8 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
9 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
10 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
11 NVIC_Init(&NVIC_InitStructure);

注意:语句“NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;”一般不能省略。除非在第一个中断配置中配置好后,后面的配置方可省略该条语句(不代表不配置,只是省略了而已)。

2.4 stm32f10x_dma.c

该文件位于“...\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src”文件夹中。一般调用该文件的函数有:

  • void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct)
  • void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState)
  • void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState)

配置方式与2.2和2.3的方式相同:先定义一个结构体,并配置相应的值(赋值),然后装载。其中,ITConfig是中断配置,如不需要写中断函数,可以不配置。

举例:

   DMA_InitTypeDef          DMA_InitStructure;

   /* DMA1 Channel6 (triggered by USART1 Rx event) Config */
DMA_DeInit(DMA1_Channel6);
DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)(&USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)RxBuffer1;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = RxBufferSize2;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel6, &DMA_InitStructure); DMA_Cmd(DMA1_Channel6, ENABLE);

说明:其中比较关键的是前4条配置(5-8行)。

2.5 stm32f10x_tim.c

该文件位于“...\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src”文件夹中。一般调用该文件的函数有:

  • void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
  • void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
  • void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)

配置方法同2.4。该文件的函数很多,可以编写出非常丰富的定时与中断函数。在本文中只是利用其中最简单的一部分:定时功能。

举例:

   TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

   /* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = ( - );
TIM_TimeBaseStructure.TIM_Prescaler = ( - );
TIM_TimeBaseStructure.TIM_ClockDivision = ;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); TIM_Cmd(TIM5, DISABLE);

注意:请留心是否需要打开定时器,否则当定时器计数并触发中断时,程序很可能一直卡在中断程序里,导致程序无法正常走下去。

2.6 stm32f10x_usart.c

该文件位于“...\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\STM32F10x_StdPeriph_Driver\src”文件夹中。一般调用该文件的函数有:

  • void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct)
  • void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState)
  • void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState)
  • void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)

配置方法同2.4-2.5。其中USART_DMACmd是配置DMA与USART通道,如不适用DMA,可以不配置。

举例:

  USART_InitTypeDef        USART_InitStructure;

/*****************************************************************************
*USART1 configured as follow: *
* - BaudRate = 9600 baud *
* - Word Length = 8 Bits *
* - One Stop Bit *
* - No parity *
* - Hardware flow control disabled (RTS and CTS signals) *
* - Receive and transmit enabled *
*****************************************************************************/
USART_InitStructure.USART_BaudRate = ;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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(USART1, &USART_InitStructure); //STM_EVAL_COMInit(COM1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);

注意:在博主的开发板上,语句“STM_EVAL_COMInit(COM1, &USART_InitStructure);”是必须的,但在有的开发板上可以不需要。调用该函数时需要调用头文件stm32_eval.h。

3 串口输出(发送)程序

3.1 关键库函数

  • void USART_SendData(USART_TypeDef* USARTx, uint16_t Data)
  • FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)

第一条语句是发送函数,它告诉我们很重要的一点,那就是串口是以”位“来传输的。如果能够理解这个概念,那么程序思路就很简单了。第二句语句作用如同其名”Get Flag Status“,可以用它来得知串口的状态。那么,结合这两个函数就可以写出自己风格和要求的串口发送函数。

3.2 利用printf改写成串口发送函数

在C编程中,最常用的便是printf,用于观察各种结果。可以利用库函数来编写类似的函数。

 /* GUC编译环境 */
#ifdef __GNUC__
With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar()
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif __GNUC__ /*************************************************
* Function Name : PUTCHAR_PROTOTYPE
* Description : Retargets the C library printf function to the USART
* Input : NONE
* Output : NONE
* Return : NONE
*************************************************/
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here
e.g. write a character to the USART */
USART_SendData(USART1, (uint8_t) ch); /* Loop until the end of transmission */
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}

函数的调用形式与c里面的printf一样。

优点:方便。

缺点:只能利用一个串口(上面程序中利用的是USART1)。当遇到多串口的时候需要对其他串口编写其他程序,在形式上就会不一致,导致程序维护起来不方便。

3.3 参考printf函数编写串口发送函数

可以参考库函数中printf函数的编写方法来自己编写一个串口的printf函数。

 #include <stdio.h>
#include <stdarg.h> /*************************************************
* Function Name : USART1_printf
* Description :
* Input :
* Output : NONE
* Return : NONE
*************************************************/
void USART1_printf (char *fmt, ...)
{
char buffer[CMD_BUFFER_LEN+];
u8 i = ; va_list arg_ptr;
va_start(arg_ptr, fmt);
vsnprintf(buffer, CMD_BUFFER_LEN+, fmt, arg_ptr);
while ((i < CMD_BUFFER_LEN) && buffer[i])
{
USART_SendData(USART1, (u8) buffer[i++]);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
va_end(arg_ptr);
}

函数的调用形式与c里面的printf一样。

优点:格式与printf一致,使用方便。

缺点:编写比较复杂。

3.4 自定义编写发送函数

根据固件库函数,可以编写出满足自己使用条件的各种发送函数,这样可以根据不同串口的特点编写出对应的函数,具有很强的针对性。

 /*************************************************
* Function Name : USART1_SendData
* Description : 串口1发送
* Input : char *Buffer
* Output : NONE
* Return : NONE
*************************************************/
void USART1_SendData(char *Buffer)
{
u8 Counter = ;
while( (Counter == ) || (Buffer[Counter] != ) ) //条件...
{
USART_SendData(USART1, Buffer[Counter++]);
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}
}

优点:自定制,编写简单。

缺点:printf字符串的时候语句不够精炼。

3.5 利用DMA发送串口数据

上述3.2-3.4的函数都需要具体在程序中调用,对CPU占用的比较厉害,而DMA的优点是不会占用CPU。

示例:

 #include "stm32f10x.h"
#include "stm32_eval.h" #define TxBufferSize1 10 u8 TxBuffer1[TxBufferSize1]; int main(void)
{
Configuration(); while();
} void Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
USART_InitTypeDef USART_InitStructure; /* Enable GPIOA and USART1 clocks */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE); /* DMA clock enable */
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* Configure USART1 Rx (PA.10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure USART1 Tx (PA.09) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure); /* Configure one bit for preemptive priority */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); /* Enable DMA Channel6 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel6_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = ;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure); /* DMA1 Channel6 (triggered by USART1 Tx event) Config */
DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)(&USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)TxBuffer1;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = TxBufferSize1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel6, &DMA_InitStructure); DMA_ITConfig(DMA1_Channel6, DMA_IT_TC, ENABLE);
DMA_Cmd(DMA1_Channel6, ENABLE); /*****************************************************************************
*USART1 configured as follow: *
* - BaudRate = 9600 baud *
* - Word Length = 8 Bits *
* - One Stop Bit *
* - No parity *
* - Hardware flow control disabled (RTS and CTS signals) *
* - Receive and transmit enabled *
*****************************************************************************/
USART_InitStructure.USART_BaudRate = ;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
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(USART1, &USART_InitStructure); //STM_EVAL_COMInit(COM1, &USART_InitStructure);
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
USART_Cmd(USART1, ENABLE); } /*************************************************
* Function Name : DMA1_Channel6_IRQHandler
* Description : DMA1_Channel6中断服务函数
* Input : NONE
* Output : NONE
* Return : NONE
*************************************************/
void DMA1_Channel6_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA1_IT_TC6);
DMA_Cmd(DMA1_Channel6, DISABLE); /* 中断程序 */ DMA_Cmd(DMA1_Channel6, ENABLE);
}

example10

注意:以上事例仅仅作为利用DMA进行串口发送的一个简要步骤。如果工程比较复杂时建议分类进行配置,否则更改起来十分费劲。其中,中断函数DMA1_Channel6_IRQHandler可以放在main.c文件中,也可以放在stm32f10x_it.c文件中,但注意拼写一定要对(中断函数的具体名称可以查看startup_stm32f10x_XX.s,“XX”表示类型)。

优点:不占用DMA,中断函数使用方便。

缺点:若考虑传输出错时的错误处理时,编程比较繁琐。

3.6 利用USART中断进行发送数据

不使用DMA进行发送,而是利用USART的中断事件进行发送,也能实现各种自定义发送。

程序待补

4 串口输入(接收)程序

4.1 关键库函数

  • uint16_t USART_ReceiveData(USART_TypeDef* USARTx)
  • FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG)

同理,第一条是逐个接收数据;第二条是获取状态。

4.2 自定义接收函数

利用上述函数可以自己定制接收函数。

示例:以回车符(\r\n)作为结束标志的接收函数

 /*************************************************
* Function Name : USART1_ReceiveData
* Description : 串口1接收
* Input : char *Buffer, u8 BufferSize
* Output : NONE
* Return : NONE
*************************************************/
void USART1_ReceiveData(char *Buffer, u8 BufferSize)
{
u8 Counter;
for(Counter = ; Counter < BufferSize ; Counter++)
Buffer[Counter] = ;
Counter = ;
do
{
if( (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) != RESET)
&&(Counter < BufferSize) )
Buffer[Counter++] = USART_ReceiveData(USART1);
if( (Counter == ) && (Buffer[Counter - ] == '\r') &&
(Buffer[Counter - ] == '\n') )
{
Buffer[] = Buffer[Counter];
Counter = ;
continue;
}
}while((Buffer[Counter - ] != '\r') || (Buffer[Counter - ] != '\n') );
for( ; Counter < BufferSize ; Counter++)
Buffer[Counter] = ;
}

说明:该函数接收的最大字长为BufferSize,遇到回车符接收完毕,且不接收空字符。关于回车符可见文章http://www.crifan.com/detailed_carriage_return_0x0d_0x0a_cr_lf__r__n_the_context/

优点:编写简单,可定制。

缺点:接收时需要调用函数,即不能作为“监听”串口是否有数据输入。

4.3 利用USART中断函数接收数据

通过中断函数来接收函数,可以做到不影响主程序的流向,从而实现对串口的接收。同样可以对中断程序进行编写达到自定义接收的效果。

示例:以回车符(\r\n)作为结束标志的接收函数

 /*************************************************
* Function Name : USART2_IRQHeader
* Description : USART2中断服务函数
* Input : NONE
* Output : NONE
* Return : NONE
*************************************************/
void USART2_IRQHandler(void)
{
u8 i;
if( USART2_Counter < RxBufferSize2 )
RxBuffer2[USART2_Counter++] = USART_ReceiveData(USART2);
if( (USART2_Counter == RxBufferSize2) ||
((USART2_Counter > ) && (RxBuffer2[USART2_Counter-] == '\r' ) &&
(RxBuffer2[USART2_Counter-] == '\n' ) ) )
{
USART2_Counter = ; /* 中断程序 */ }
USART_ClearITPendingBit(USART2, USART_IT_RXNE);
}

优点:可定制,占用CPU少,不影响主程序的走向。

缺点:需要配置中断函数。

4.4 利用DMA接收定长数据

详见3.5。可以利用DMA接收定长的数据,对于定长数据传输时能做到不占用CPU,高效率的传输。

优点:速度快,适合与定长传输、海量数据传输。

缺点:定长

4.5 利用DMA接收不定长数据

其思路有两种:一种是外部时钟加内部编程,即Rx端外加一个时钟引脚,利用时钟来判定是否停止接收。其优点是“软硬结合,编程简单”,缺点是对于不熟悉时钟操作的人来说操作起来有一定难度。

另一种方法是利用STM32内部的定时器编程的方法触发另一个中断程序。通过波特率计算出传输一位(8bit)的时间,定时器设置约为传输一位(8bit)的时间,通过判断DMA内数组长度(指针位置)是否改变从而触发事件。

示例:

 u8   TIM4_Counter   = ;
bool TIM4_i = ;
bool TIM4_j = ; /*************************************************
* Function Name : TIM4_IRQHandler
* Description : TIM4中断服务函数
* Input : NONE
* Output : NONE
* Return : NONE
*************************************************/
void TIM4_IRQHandler(void)
{
TIM_ClearITPendingBit(TIM4, TIM_IT_Update);
TIM_Cmd(TIM4, DISABLE); if(!TIM4_i)
{
TIM4_Counter = RxBufferSize2 - DMA_GetCurrDataCounter(DMA1_Channel6);
TIM4_i = ;
}
else if(TIM4_Counter != (RxBufferSize2 - DMA_GetCurrDataCounter(DMA1_Channel6)) )
TIM4_i = ;
else if( (!TIM4_j) && (TIM4_Counter != ) && (TIM4_Counter != RxBufferSize2) )
{
TIM4_i = ;
DMA_Cmd(DMA1_Channel6, DISABLE);
DMA1_Channel6->CNDTR = RxBufferSize2; //重装初值 /* 中断程序 */ DMA_Cmd(DMA1_Channel6, ENABLE);
}
else if(TIM4_j)
{
TIM4_i = ;
TIM4_j = ;
} TIM_Cmd(TIM4, ENABLE);
}
/*************************************************
* Function Name : DMA1_Channel6_IRQHandler
* Description : DMA1_Channel6中断服务函数
* Input : NONE
* Output : NONE
* Return : NONE
*************************************************/
void DMA1_Channel6_IRQHandler(void)
{
DMA_ClearITPendingBit(DMA1_IT_TC6);
DMA_Cmd(DMA1_Channel6, DISABLE);
DMA1_Channel6->CNDTR = RxBufferSize2; //重装初值
TIM4_j = ; /* 中断程序 */ DMA_Cmd(DMA1_Channel6, ENABLE);
}

优点:不定长DMA接收数据

缺点:程序复杂。

5 结语

以上便是基于STM32F10x的串口输入输出编程,其程序都经过测试可行。但由于编写文章时难免有些疏漏,程序如有问题,可在下方留言,我会尽快修改。如果有地方说的不正确的也请指明,我也会积极修改并给出回复。如果有其他意见和建议,也可以在后面留言,我会尽快答复。

最后声明一点,其中代码所蕴含的思想,或者说程序本身,并非博主所有,博主所做的仅仅是一种经验上的总结,如果有那些部分是私用了您的版权,请私下联系我并出示证明,我会尽快处理。如果此文章对您有所启发,也欢迎转载,转载时请注明文章出处,谢谢!

6 附件

图1出处为《STM32F系列ARM内核32位高性能微控制器参考手册V14.pdf》. 48页。

基于STM32F10x的串口(USART)输入输出编程的更多相关文章

  1. STM32串口usart发送数据

    主函数请直接关注41行到47行代码!! #include "stm32f10x.h" // 相当于51单片机中的 #include <reg51.h> #include ...

  2. stm32串口USART 硬件流控 --学习笔记

    流控的概念源于 RS232 这个标准,在 RS232 标准里面包含了串口.流控的定义.大家一定了解,RS232 中的"RS"是Recommend Standard 的缩写,即&qu ...

  3. 基于引擎的matlab+vc混合编程的配置

    前段时间在项目中做了一些关于基于引擎的vc+matlab混合编程的工作. 如果你是混合编程新手,我相信使用引擎的方式编程是比较简单快捷的一种方式. 当然这种方法也有其缺点,就是不能脱离matlab运行 ...

  4. atitit.基于组件的事件为基础的编程模型--服务器端控件(1)---------服务器端控件和标签之间的关系

    atitit.基于组件的事件为基础的编程模型--服务器端控件(1)---------服务器端控件和标签之间的关系 1. server控件是要server了解了标签.种类型的server控件: 1 1. ...

  5. Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探

    由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...

  6. Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AOP编程比较

    本篇博文用一个稍复杂点的案例来对比一下基于XML配置与基于AspectJ注解配置的AOP编程的不同. 相关引入包等Spring  AOP编程准备,请参考小编的其他博文,这里不再赘述. 案例要求: 写一 ...

  7. 基于树莓派3的CAN总线编程

    基于树莓派3的CAN总线编程 原创 2016年09月08日 10:16:13 标签: 树莓派3 / MCP2515 / CAN总线 / python / 命令行 5254 简介 树莓派3使用Pytho ...

  8. 【Delphi】基于状态机的串口通信

    通信协议 串行通信接口(如RS232.RS485等)作为计算机与单片机交互数据的主要接口,广泛用于各类仪器仪表.工业监测及自动控制领域中. 通信协议是需要通信的双方所达成的一种约定,它对包括数据格式. ...

  9. 串口(USART)框图的讲解

    STM32 的 USART 简介 通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备,可以灵 ...

随机推荐

  1. java代理

    首先,java中为什么要提出代理的设计模式呢?代理模式的作用是:为其它对象提供一种代理以控制对这个对象的訪问.在某些情况下,一个客户不想或者不能直接引用还有一个对象,而代理对象能够在client和目标 ...

  2. [TypeScript] Loading Compiled TypeScript Files in Browser with SystemJS

    TypeScript outputs JavaScript, but what are you supposed to do with it? This lesson shows how to tak ...

  3. allocator例子

    13.39 编写自己的StrVec,包括自己版本的reserve.capacity和resize. 13.40 为StrVec添加一个构造函数,它接受一个initializer_list<str ...

  4. 基于事件的 NIO 多线程服务器--转载

    JDK1.4 的 NIO 有效解决了原有流式 IO 存在的线程开销的问题,在 NIO 中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个 CPU 的处 ...

  5. 【NodeJs】用arrayObject.join('')处理粘包的错误原因

    服务器测试代码如下: var net = require('net'); var server = net.createServer(function(c){ console.log('client ...

  6. JSP/Servlet 中的事件处理

    写过AWT或Swing程序的人一定对桌面程序的事件处理机制印象深刻:通过实现Listener接口的类可以在特定事件(Event)发生时,呼叫特定的方法来对事件进行响应. 其实我们在编写JSP/Serv ...

  7. Android(java)学习笔记192:SQLite数据库(表)的创建 以及 SQLite数据库的升级

    一.数据库的创建 1.文件的创建      //引用,如果文件不存在是不会创建的   File  file = new File("haha.txt"):     //输出流写数据 ...

  8. idea集成svn插件

    1.需要在机器上安装一个SVN客户端命令行程序,可以到这里下载对应的安装程序:http://subversion.apache.org/packages.html#windows 我选择的是torto ...

  9. 学习java随笔第六篇:数组

    一维数组 创建一维数组并输出 public class OneDimensionalArray { public static void main(String argas[]) { int i[]= ...

  10. c#中var关键字用法

    Technorati 标签: C# 转载自csdn:http://blog.csdn.net/robingaoxb/article/details/6175533   var关键字是C# 3.0开始新 ...