10.1 通信基本概念10.1.1 并行通信和串行通信1、处理器与外部设备通信的两种方式:串行通信有两种通信方式: 并行通信: -传输原理:数据各个位同时传输。 -优点:速度快 -缺点:占用引脚资源多 串行通信 -传输原理: 串行通信方式有 UART USB IIC SPI CAN 以太网等都是采用串行通信方式。 数据按位顺序传输。 -优点:占用引脚资源少 -缺点:速度相对较慢 不过这两种通信方式是可以转换的,如图串行转并行:
有关两者优缺点: 10.1.2 单工通信、半双工通信、全双工通信按照数据传送方向,分为: 单工: 数据传输只支持数据在一个方向上传输; 半双工: 允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信; 全双工: 允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。 11.1.3 同步通信和异步通信1、同步通信:带时钟同步信号传输。2、 异步通信:不带时钟同步信号。10.1.4 RS-2321、RS232标准串口通讯结构图2、原生的串口通信10.1.5 串口数据帧格式1、串口数据包的基本组成2、奇偶校验10.2 STM32F429 USART结构10.2.1 概述10.2.2 USART结构2、数据通道3、发送器4、接收器10.2.3 波特率设置10.2.4 DMA控制接收缓冲区和发送缓冲区的DMA请求是独立的,它们分别对应于独立的DMA通道。 1.使用DMA进行发送将USART控制寄存器3(USART_CR3)中的DMAT位置1可以使能DMA模式进行发送。 一旦使能了USART的DMA功能,当TXE 位置1时, 控制器会将数据自动从SRAM区加载到USART_DR,启动发送过程。 所有数据的发送不需要通过程序干涉。 2.使用DMA进行接收将USART_CR3中的DMAR位置1可以使能DMA模式进行接收。一旦使能了USART的DMA功能,当接收数据时,RXNE 位置1时,控制器会将数据会从USART_DR自动加载到SRAM区域中。整个数据的接受过程不需要程序的干涉。 10.3 USART典型应用步骤及常用库函数10.3.1 串口配置一般步骤10.3.2 常用库函数说明10.4 应用实例10.4.1 通过串口向计算机传输100个字节使用串口线把计算机和电路板的USART1连接在一起,如图11-15所示。编写程序,通过USART1向计算机发送100个字节,这一功能可以通过查询方式、中断方式或中断方式实现。这里以常用的查询方式实现这一功能。 USART1配置参数: 波特率=115 200、 有效数据位=8位、 停止位=1位、 不使用校验方式、 收发模式、 不使用硬件流控。 USART1的TXD和RXD分别使用PA9和PA10。 1.编程要点(1)使能USART1和复用引脚GPIO的工作时钟。 (2)初始化USART1 相关GPIO引脚,并将引脚复用给USART1。 (3)根据要求,初始化USART1。使用查询方式发送数据。 (4)使能USART1。 (5)循环发送100个字节。 2.主程序int main(void){ uint16_t i; /*初始化USART 配置模式为 115200 8-N-1,中断接收*/USART1_Config();for(i=0;i<100;i++)//循环发送100个x {/*发送一个字符x*/USART_SendData(USART1, 'x’);/*等待发送数据寄存器为空 ,只有在发送数据寄存器为空的情况下,才能发送下一个字符*/while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); }while(1); }
3. 串口配置函数void USART_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; /*-------------------第1步--------------------*/ /*使能 GPIOA时钟*/ RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA,ENABLE); /*使能 UART1 时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); /*-------------------第2步--------------------*/ /*复用PA9到USART1*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); /*复用PA10到USART1*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); /*配置TX引脚为复用功能*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用模式 GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); /*配置RX引脚为复用功能*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF ; //复用模式 GPIO_Init(GPIOA,&GPIO_InitStructure); /*-------------------第3步--------------------*/ /*配置USART1模式*/ USART_InitStructure.USART_BaudRate = 115200; //波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位有效数据位 USART_InitStructure.USART_StopBits = USART_StopBits_1; //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); //初始化USART1/*因为使用查询方式发送数据,没有用到中断,因此没有中断相关配置,缺少第4步*/ /*-------------------第5步--------------------*/ USART_Cmd(USART1, ENABLE);//使能USART1}
10.4.2 串口与计算机回显功能实现回显功能就是把计算机发送给电路板上微控制器的数据通过串口原样返回给计算机,并显示在串口显示软件中。 USART1配置参数: 波特率=115 200、 有效数据位=8位、 停止位=1位、 不使用校验方式、 收发模式、 不使用硬件流控。 USART1的TXD和RXD分别使用PA9和PA10。 1.编程要点(1)使能USART1和复用引脚GPIO的时钟。 (2)初始化USART1 相关GPIO引脚,并将引脚复用给USART1。 (3)根据要求初始化USART1。 (4)初始化NVIC的USART1串口中断通道,并使能USART1的读取数据寄存器不为空中断(RXNE)。 (5)使能USART1。 (6)编写中断服务程序。 2.主程序int main(void){ USART_Config(); //初始化USART1 printf('这是一个串口中断接收回显实验\n');//注意只有对printf函数进行重定向才能使用 while(1);}
3. 串口配置函数void USART_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; /*-------------------第1步--------------------*/ /*使能 GPIOA时钟*/ RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA,ENABLE); /*使能 UART1 时钟*/ RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); /*-------------------第2步--------------------*/ /*复用PA9到USART1*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); /*复用PA10到USART1*/ GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); /*配置TX引脚为复用功能*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF; //复用模式 GPIO_InitStructure.GPIO_OType=GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); /*配置RX引脚为复用功能*/ GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF ; //复用模式 GPIO_Init(GPIOA,&GPIO_InitStructure); /*-------------------第3步--------------------*/ /*配置USART1模式*/ USART_InitStructure.USART_BaudRate = 115200; //波特率 USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位有效数据位 USART_InitStructure.USART_StopBits = USART_StopBits_1; //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); //初始化USART1 /*-------------------第4步--------------------*///初始化NVIC中的USART1中断通道NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //选择NVIC组2NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn; //配置USART为中断源NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1; //抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority=1; //响应优先级为1NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能中断 NVIC_Init(&NVIC_InitStructure); //初始化配置NVIC //使能串口的RXNE中断USART_ITConfig(USART1,USART_IT_RXNE,ENABLE); //使能串口的RXNE中断/*-------------------第5步--------------------*/USART_Cmd(USART1,ENABLE); //使能USART1}
4.串口中断服务函数void USART1_IRQHandler(void){uint8_t ucTemp;if(USART_GetITStatus(USART1,USART_IT_RXNE)!=RESET) //检测RXNE标志位{ ucTemp = USART_ReceiveData( USART1 ); //读取接收数据USART_SendData(USART1,ucTemp); //把数据发送给计算机,实现回显功能 } }
5. printf函数重定向使用printf函数通过USART1向计算机的串口调试助手打印数据,需要将printf函数内部实现功能重定向到微控制器的USART1。 (1)设置Keil MDK软件中的Use MicroLIB选项。 (2)重定向fputc函数。 (2)重定向fputc函数。int fputc(int ch, FILE* stream){//通过串级发送数据chUSART_SendData(USART1, (uint8_t) ch); while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //等待发送完毕 return ch;}
10.4.3 利用DMA通过串口向计算机1000个字节利用DMA通过USART1向计算机传输1000个字节,一旦配置好USART1和DMA数据流,在启动DMA传输之后,不需要程序的干预,即可完成数据传输 USART1配置参数:波特率=115 200、有效数据位=8位、停止位=1位、不使用校验方式、收发模式、不使用硬件流控。 1.编程要点(1)使能USART1、复用引脚GPIO及DMA2的时钟。 (2)初始化USART1相关GPIO引脚,并将引脚复用给USART1。 (3)根据要求,初始化并使能USART1。 (4)初始化DMA2数据流7的通道4,并使能DMA2数据流7。 (5)使能USART1的DMA发送功能,启动DMA数据传输。 2、主程序uint8_t Send_Buff[1000]; //DMA传输数据源存储区int main(void){uint16_t i;USART_Config(); //初始化USART1DMA_Config(); //初始化DMAfor(i=0;i<SENDBUFF_SIZE;i++) //初始化DMA传输数据源存储区{Send_Buff [i] = 'Z';}/*使能USART1的DMA发送,启动DMA数据传输*/USART_DMACmd(USART1, USART_DMAReq_Tx,ENABLE); //关键while(1); //无须CPU干涉,实现数据传输}
3. 串口配置函数同10.4.1串口配置函数。 4. DMA配置函数extern uint8_t Send_Buff[1000]; //DMA传输数据源存储区void DMA_Config(void){ DMA_InitTypeDef DMA_InitStructure; /*-------------------第1步--------------------*/ RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE); //使能DMA2时钟 /*-------------------第2步--------------------*/ DMA_DeInit(DMA2_Stream7); //复位,禁止DMA2数据流7while (DMA_GetCmdStatus(DMA2_Stream7)!= DISABLE); //确保DMA数据流禁止成功/*-------------------第3步--------------------*/ /*初始化DMA2数据流7*/DMA_InitStructure.DMA_Channel=DMA_Channel_7; //选择通道DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t) SRC_Buffer;//目标地址DMA_InitStructure.DMA_Memory0BaseAddr=(uint32_t) Send_Buff; //源数据地址DMA_InitStructure.DMA_DIR=DMA_DIR_MemoryToPeripheral; //存储器到外设模式DMA_InitStructure.DMA_BufferSize=1000; //DMA传输数据数目//禁止自动递增功能DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable; //使能自动递增功能//8位数据宽度DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;DMA_InitStructure.DMA_MemoryDataSize=DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_Mode=DMA_Mode_Normal; //正常模式,不循环,只传输一次 DMA_InitStructure.DMA_Priority=DMA_Priority_High;//设置DMA2数据流7优先级为高DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable; //禁用FIFO模式 //此时这一参数无用DMA_InitStructure.DMA_FIFOThreshold=DMA_FIFOThreshold_Full; DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single; //单次模式DMA_InitStructure.DMA_PeripheralBurst=DMA_MemoryBurst_Single; //单次模式DMA_Init(DMA2_Stream7,&DMA_InitStructure); //完成DMA2数据流7配置 /*-------------------第4步--------------------*/ DMA_Cmd(DMA2_Stream7,ENABLE); //使能DMA2数据流7,启动DMA数据传输 /*-------------------第5步--------------------*/ while (DMA_GetCmdStatus(DMA2_Stream7)!=ENABLE); //检测DMA数据流是否有效}
|