基于STM32F10x的串口(USART)输入输出编程
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)输入输出编程的更多相关文章
- STM32串口usart发送数据
主函数请直接关注41行到47行代码!! #include "stm32f10x.h" // 相当于51单片机中的 #include <reg51.h> #include ...
- stm32串口USART 硬件流控 --学习笔记
流控的概念源于 RS232 这个标准,在 RS232 标准里面包含了串口.流控的定义.大家一定了解,RS232 中的"RS"是Recommend Standard 的缩写,即&qu ...
- 基于引擎的matlab+vc混合编程的配置
前段时间在项目中做了一些关于基于引擎的vc+matlab混合编程的工作. 如果你是混合编程新手,我相信使用引擎的方式编程是比较简单快捷的一种方式. 当然这种方法也有其缺点,就是不能脱离matlab运行 ...
- atitit.基于组件的事件为基础的编程模型--服务器端控件(1)---------服务器端控件和标签之间的关系
atitit.基于组件的事件为基础的编程模型--服务器端控件(1)---------服务器端控件和标签之间的关系 1. server控件是要server了解了标签.种类型的server控件: 1 1. ...
- Spring学习之旅(八)Spring 基于AspectJ注解配置的AOP编程工作原理初探
由小编的上篇博文可以一窥基于AspectJ注解配置的AOP编程实现. 本文一下未贴出的相关代码示例请关注小编的上篇博文<Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AO ...
- Spring学习之旅(七)基于XML配置与基于AspectJ注解配置的AOP编程比较
本篇博文用一个稍复杂点的案例来对比一下基于XML配置与基于AspectJ注解配置的AOP编程的不同. 相关引入包等Spring AOP编程准备,请参考小编的其他博文,这里不再赘述. 案例要求: 写一 ...
- 基于树莓派3的CAN总线编程
基于树莓派3的CAN总线编程 原创 2016年09月08日 10:16:13 标签: 树莓派3 / MCP2515 / CAN总线 / python / 命令行 5254 简介 树莓派3使用Pytho ...
- 【Delphi】基于状态机的串口通信
通信协议 串行通信接口(如RS232.RS485等)作为计算机与单片机交互数据的主要接口,广泛用于各类仪器仪表.工业监测及自动控制领域中. 通信协议是需要通信的双方所达成的一种约定,它对包括数据格式. ...
- 串口(USART)框图的讲解
STM32 的 USART 简介 通用同步异步收发器(Universal Synchronous Asynchronous Receiver and Transmitter)是一个串行通信设备,可以灵 ...
随机推荐
- java代理
首先,java中为什么要提出代理的设计模式呢?代理模式的作用是:为其它对象提供一种代理以控制对这个对象的訪问.在某些情况下,一个客户不想或者不能直接引用还有一个对象,而代理对象能够在client和目标 ...
- [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 ...
- allocator例子
13.39 编写自己的StrVec,包括自己版本的reserve.capacity和resize. 13.40 为StrVec添加一个构造函数,它接受一个initializer_list<str ...
- 基于事件的 NIO 多线程服务器--转载
JDK1.4 的 NIO 有效解决了原有流式 IO 存在的线程开销的问题,在 NIO 中使用多线程,主要目的已不是为了应对每个客户端请求而分配独立的服务线程,而是通过多线程充分使用用多个 CPU 的处 ...
- 【NodeJs】用arrayObject.join('')处理粘包的错误原因
服务器测试代码如下: var net = require('net'); var server = net.createServer(function(c){ console.log('client ...
- JSP/Servlet 中的事件处理
写过AWT或Swing程序的人一定对桌面程序的事件处理机制印象深刻:通过实现Listener接口的类可以在特定事件(Event)发生时,呼叫特定的方法来对事件进行响应. 其实我们在编写JSP/Serv ...
- Android(java)学习笔记192:SQLite数据库(表)的创建 以及 SQLite数据库的升级
一.数据库的创建 1.文件的创建 //引用,如果文件不存在是不会创建的 File file = new File("haha.txt"): //输出流写数据 ...
- idea集成svn插件
1.需要在机器上安装一个SVN客户端命令行程序,可以到这里下载对应的安装程序:http://subversion.apache.org/packages.html#windows 我选择的是torto ...
- 学习java随笔第六篇:数组
一维数组 创建一维数组并输出 public class OneDimensionalArray { public static void main(String argas[]) { int i[]= ...
- c#中var关键字用法
Technorati 标签: C# 转载自csdn:http://blog.csdn.net/robingaoxb/article/details/6175533 var关键字是C# 3.0开始新 ...