OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 10548|回复: 10

stm32 串口2 问题

[复制链接]

23

主题

74

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2012-3-15
在线时间
13 小时
发表于 2013-5-13 16:12:54 | 显示全部楼层 |阅读模式

使用原子的485源程序 修改如下,现在在串口调试助手里面看到的都是乱码
///////////////////////////////串口2///////////////////////////////////////////////////    

#ifdef EN_USART2_RX    //如果使能了接收     
//接收缓存区  
u8 USART2_RX_BUF[64];   //接收缓冲,最大64个字节.
//接收到的数据长度
u8 USART2_RX_CNT = 0;  
void USART2_IRQHandler(void)
{
 u8 res;    
 if(USART2->SR & (1 << 5))//接收到数据
 { 
  res = USART2->DR;    
  if(USART2_RX_CNT < 64)
  {
   USART2_RX_BUF[USART2_RX_CNT] = res;  //记录接收到的值
   USART2_RX_CNT++;      //接收数据增加1
  }
 }             
}
#endif          
//初始化IO 串口2
//pclk1CLK1时钟频率(Mhz)
//bound:波特率  
void USART2_Init(u32 pclk1, u32 bound)
{   
 float temp;
 u16 mantissa;
 u16 fraction;   
 temp = (float)(pclk1 * 1000000) / (bound * 16);//得到USARTDIV
 mantissa = temp;     //得到整数部分
 fraction = (temp - mantissa) * 16; //得到小数部分 
    mantissa <<= 4;
 mantissa += fraction;
 
 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 = mantissa;  // 波特率设置 
 USART2->CR1 |= 0X200C;   //1位停止,无校验位.
#ifdef EN_USART2_RX     //如果使能了接收
 //使能接收中断
 USART2->CR1 |= 1 << 8;     //PE中断使能
 USART2->CR1 |= 1 << 5;     //接收缓冲区非空中断使能      
 MY_NVIC_Init(3, 3, USART2_IRQChannel, 2);//组2,最低优先级
#endif
}

//USART2发送len个字节.
//buf:发送区首地址
//len:发送的字节数(为了和本代码的接收匹配,这里建议不要超过64个字节)
void USART2_Send_Data(u8 *buf, u8 len)
{
 u8 t;
   for(t = 0; t < len; t++)  //循环发送数据
 {
  while((USART2->SR & 0X40) == 0);//等待发送结束   
  USART2->DR = buf[t];
 } 
 while((USART2->SR & 0X40) == 0);//等待发送结束 
 USART2_RX_CNT = 0;  
}
//USART2查询接收到的数据
//buf:接收缓存首地址
//len:读到的数据长度
void USART2_Receive_Data(u8 *buf, u8 *len)
{
 u8 rxlen = USART2_RX_CNT;
 u8 i = 0;
 *len = 0;    //默认为0
 delay_ms(10);  //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
 if(rxlen == USART2_RX_CNT && rxlen)//接收到了数据,且接收完成了
 {
  for(i = 0; i < rxlen; i++)
  {
   buf = USART2_RX_BUF
  }  
  *len = USART2_RX_CNT; //记录本次数据长度
  USART2_RX_CNT = 0;  //清零
 }
}


//重定义fputc函数
int fputc(int ch, FILE *f)
{     
 //while((USART1 -> SR & 0X40) == 0);//循环发送,直到发送完毕  
 //USART1->DR = (u8) ch;
 while((USART2 -> SR & 0X40) == 0);//循环发送,直到发送完毕  
 USART2->DR = (u8) ch;          
 return ch;
}


void hardware_test(void)
{
 printf("\r\n%s\r\n", "串口2调试"); 
 delay_ms(100);  
}

int main(void)
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            {
 stm32_init();
 hardware_init();

 while(1)
 {

   hardware_test();

 } 
}



正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-5-13 17:21:06 | 显示全部楼层
直接用我们的代码就可以用啊。
把PA2,PA3连接到RS232这端,然后接上串口到电脑,波特率设置为9600,就可以正常收发数据了。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-5-13 17:21:18 | 显示全部楼层
注意以hex方式发送和接收
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-5-13 17:21:41 | 显示全部楼层
如果要用printf,请参考我们的GSM模块例程,GPS模块例程,或者蓝牙模块例程。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

23

主题

74

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2012-3-15
在线时间
13 小时
 楼主| 发表于 2013-5-13 17:27:57 | 显示全部楼层
回复【4楼】正点原子:
---------------------------------
我参考蓝牙的程序在主函数里面循环发送
u2_printf("\r\n%s\r\n", "串口2调试");
delay_ms(100);
结果还是乱码 波特率也是对的。
回复 支持 反对

使用道具 举报

23

主题

74

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2012-3-15
在线时间
13 小时
 楼主| 发表于 2013-5-13 17:28:37 | 显示全部楼层
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "stdarg.h"    
#include "stdio.h"    
#include "string.h"    
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_UCOS

#include "includes.h"//ucos 使用
  
#endif

/*************************************************************************
V1.3修改说明 
支持适应不同频率下的串口波特率设置.
加入了对printf的支持
增加了串口接收命令功能.
修正了printf第一个字符丢失的bug
V1.4修改说明
1,修改串口初始化IO的bug
2,修改了USART_RX_STA,使得串口最大接收字节数为2的14次方
3,增加了USART_REC_LEN,用于定义串口最大允许接收的字节数(不大于2的14次方)
4,修改了EN_USART1_RX的使能方式
V1.5修改说明
1,增加了对UCOSII的支持
**************************************************************************/    
 
//加入以下代码,支持printf函数,而不需要选择use MicroLIB   
#if 1

#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 

int handle; 
/* Whatever you require here. If the only file you are using is */ 
/* standard output using printf() for debugging, no file handling */ 
/* is required. */ 
}; 
/* FILE is typedef’ d in stdio.h. */ 
FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
_sys_exit(int x) 

x = x; 

//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
while((USART1 -> SR & 0X40) == 0);//循环发送,直到发送完毕   
USART1->DR = (u8) ch;       
return ch;
}

#endif 

#if EN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   
u8 USART_RX_BUF[USART_REC_LEN];     //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA = 0;       //接收状态标记   
  
void USART1_IRQHandler(void)
{
u8 res;
#ifdef OS_CRITICAL_METHOD  //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
OSIntEnter();    
#endif
if(USART1->SR & (1 << 5))//接收到数据
{  
res = USART1->DR; 
if((USART_RX_STA & 0x8000) == 0)//接收未完成
{
if(USART_RX_STA & 0x4000)//接收到了0x0d
{
if(res != 0x0a)USART_RX_STA = 0;//接收错误,重新开始
else USART_RX_STA |= 0x8000; //接收完成了 
}else //还没收到0X0D
{
if(res == 0x0d)USART_RX_STA |= 0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF] = res;
USART_RX_STA++;
if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0;//接收数据错误,重新开始接收   
}  
}
}          
}
#ifdef OS_CRITICAL_METHOD  //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
OSIntExit();    
#endif

#endif  
//初始化IO 串口1
//pclk2CLK2时钟频率(Mhz)
//bound:波特率
//CHECK OK
//091209
void uart_init(u32 pclk2, u32 bound)
{    
float temp;
u16 mantissa;
u16 fraction;    
temp = (float)(pclk2 * 1000000) / (bound * 16);//得到USARTDIV
mantissa = temp;  //得到整数部分
fraction = (temp - mantissa) * 16; //得到小数部分  
    mantissa <<= 4;
mantissa += fraction; 
RCC->APB2ENR |= 1 << 2;   //使能PORTA口时钟  
RCC->APB2ENR |= 1 << 14;  //使能串口时钟 
GPIOA->CRH &= 0XFFFFF00F;//IO状态设置
GPIOA->CRH |= 0X000008B0;//IO状态设置
  
RCC->APB2RSTR |= 1 << 14;   //复位串口1
RCC->APB2RSTR &= ~(1 << 14);//停止复位        
//波特率设置
  USART1->BRR = mantissa; // 波特率设置  
USART1->CR1 |= 0X200C;  //1位停止,无校验位.
#if EN_USART1_RX   //如果使能了接收
//使能接收中断
USART1->CR1 |= 1 << 8;    //PE中断使能
USART1->CR1 |= 1 << 5;    //接收缓冲区非空中断使能     
MY_NVIC_Init(3, 3, USART1_IRQChannel, 2);//组2,最低优先级 
#endif
}
///////////////////////////////串口2///////////////////////////////////////////////////     
void TIM4_Set(u8 sta);
void TIM4_Init(u16 arr,u16 psc);
void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar);
void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len);

//串口发送缓存区 
__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
//pclk1CLK1时钟频率(Mhz)
//bound:波特率   
void USART2_Init(u32 pclk1,u32 bound)
{      
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_IRQChannel, 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->SC = psc;   //预分频器
  TIM4->DIER |= 1 << 0;   //允许更新中断
  TIM4->CR1 |= 0x01;   //使能定时器4       
    MY_NVIC_Init(1, 3, TIM4_IRQChannel, 2);//抢占2,子优先级3,组2 在2中优先级最低  
}
#endif  
///////////////////////////////////////USART2 DMA发送配置部分//////////////////////////////////         
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHxMA通道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传输
}    
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////   






---------------
#ifndef __USART_H__
#define __USART_H__

#include "sys.h"
#include "stdio.h"  

/************************************************************************
V1.3修改说明 
支持适应不同频率下的串口波特率设置.
加入了对printf的支持
增加了串口接收命令功能.
修正了printf第一个字符丢失的bug
V1.4修改说明
1,修改串口初始化IO的bug
2,修改了USART_RX_STA,使得串口最大接收字节数为2的14次方
3,增加了USART_REC_LEN,用于定义串口最大允许接收的字节数(不大于2的14次方)
4,修改了EN_USART1_RX的使能方式
V1.5修改说明
1,增加了对UCOSII的支持
***************************************************************************/ 

#define USART_REC_LEN   512   //定义最大接收字节数 512
#define EN_USART1_RX  1 //使能:1; 禁止0.串口1接收

//////////////////////////////////////串口2//////////////////////////////////////////////////////  
#define USART2_MAX_RECV_LEN 200 //最大接收缓存字节数
#define USART2_MAX_SEND_LEN 200 //最大发送缓存字节数
#define USART2_RX_EN  1 //0,不接收;1,接收.

extern u8  USART2_RX_BUF[USART2_MAX_RECV_LEN];  //接收缓冲,最大USART2_MAX_RECV_LEN字节
extern u8  USART2_TX_BUF[USART2_MAX_SEND_LEN];  //发送缓冲,最大USART2_MAX_SEND_LEN字节
extern u16 USART2_RX_STA;    //接收数据状态
/////////////////////////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////串口2//////////////////////////////////////////////////////  
void USART2_Init(u32 pclk2,u32 bound);
void USART2_Send_Data(u8 *buf,u8 len);
void USART2_Receive_Data(u8 *buf,u8 *len);
void u2_printf(char* fmt,...);
/////////////////////////////////////////////////////////////////////////////////////////////////   
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符 
extern u16 USART_RX_STA;          //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 pclk2, u32 bound);

#endif
回复 支持 反对

使用道具 举报

23

主题

74

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
222
金钱
222
注册时间
2012-3-15
在线时间
13 小时
 楼主| 发表于 2013-5-13 17:29:11 | 显示全部楼层
Stm32_Clock_Init(9); //72M
delay_init(72); //延时初始化
uart_init(72, 9600);  //串口初始化为9600
USART2_Init(36, 9600);
Timerx_Init(5000, 7199);//10Khz的计数频率,计数到5000为500ms
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2013-5-13 20:35:06 | 显示全部楼层
那怪了,我的很正常哦。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

10

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
90
金钱
90
注册时间
2014-5-17
在线时间
0 小时
发表于 2014-7-25 13:37:59 | 显示全部楼层
回复【8楼】正点原子:
---------------------------------
原子问一下, 我现在有个自己的通信模块,它默认是引出的USART2的TX,RX两个引脚,我怎么把这个连到stm32战舰版上把这个通信模块发送的数据显示到pc串口助手上? 是不是把这个通信模块接到PA9,PA10对面的那个Rx,TX上然后用那个串口试验的代码就可以了? 那个好像是只有从串口助手上接收数据然后显示出来的功能是吧? 那我这个是直接接受通信模块的数据然后送到pc串口助手上显示要怎么弄?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2014-7-25 23:18:39 | 显示全部楼层
回复【9楼】stm3201:
---------------------------------
你要是直接电脑串口助手看,那就把你的模块接USB转串口就可以了.
不过你要确认你的TX,RX是不是RS232?还是TTL?
电平必须匹配才行.
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

1

主题

10

帖子

0

精华

初级会员

Rank: 2

积分
90
金钱
90
注册时间
2015-8-9
在线时间
13 小时
发表于 2016-3-30 14:34:24 | 显示全部楼层
正点原子 发表于 2013-5-13 17:21
直接用我们的代码就可以用啊。
把PA2,PA3连接到RS232这端,然后接上串口到电脑,波特率设置为9600,就可以 ...

原子哥,请问一下,能否想串口1那样,用串口2下载程序并收发数据。。??
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-20 06:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表