打印

【奇怪问题】USART通信死机

[复制链接]
2977|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
fymok|  楼主 | 2011-9-26 13:49 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 fymok 于 2011-9-26 13:50 编辑

大家好,我单片机用的是stm32f103RE,64脚封装的。USART通信遇到了问题,请大家帮忙指教!

不胜感激!

上位机通过USART1向下位机发送一串十六进制数 如 AA 78 01 06 CC 33 C3 3C,
其中0xAA 0x78为一帧数据的开始,0xCC,0x33,0xC3,0x3C为一帧数据的结束,中间两个字节为要发送的数据。

程序实现的功能:下位机收到后通过USART2 向上位机返回收到的数。

遇到的问题:上位机第一次发送数据后,程序中的变量i1=8,下位机返回数据正确,上位机第二次发送数据后,单片机能进中断,但usart1接收缓存中的数据不对,并且此时i1=1,程序死机。复位后,上述问题重复。


主函数
/*******************************************************************************
* File Name          : main.c
* Author             : Nanjing
* Date First Issued  : 22/09/2011
* Description        : Main program body
*  
********************************************************************************
* History:
* 09/22/2011: V0.1
********************************************************************************
* AD采样PC0口分压的值,将采样值每间隔1s向串口发送一次
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "stdio.h"
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define ADC1_DR_Address    ((uint32_t)0x4001244C)    //0x40012400+0x4C,指的是ADC_DR
#define Tim_1ms 0x15a9              // 5545                    
#define Tim_10ms Tim_1ms * 10
#define Tim_1s Tim_1ms * 1000
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
ADC_InitTypeDef   ADC_InitStructure;
DMA_InitTypeDef   DMA_InitStructure;
uint32_t AD_value;
extern volatile uint8_t flag;
__IO uint16_t ADC1ConvertedValue = 0;
  uint8_t j1 = 0 ,j2 = 0;
extern char RX_dat1[100], RX_dat2[100];
extern volatile uint8_t uart_flag1,uart_flag2;
extern volatile uint8_t t2;
  uint32_t ADC_filter(void);
ErrorStatus HSEStartUpStatus;

/* Private function prototypes -----------------------------------------------*/
void RCC_Configuration(void) ;
void GPIO_Configuration(void);
void USART_Configuration(void);
void NVIC_Configuration(void);
    void Delay(vu32 nCount);


/* Private functions ---------------------------------------------------------*/
/*******************************************************************************
* Function Name  : main
* Description    : Main program.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
int main(void)
{
#ifdef DEBUG
debug() ;
#endif

  /* Configure the system clocks */
RCC_Configuration();
/* Configure the GPIO ports */
GPIO_Configuration();
/* Configure the EXTI */
NVIC_Configuration();
USART_Configuration();
  /* DMA1 channel1 configuration ----------------------------------------------*/
  DMA_DeInit(DMA1_Channel1);  //开启DMA1的第一通道
  DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;    //DMA对应的外设基地址,这个地址从Datasheet查
  DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC1ConvertedValue;  //该参数用以定义DMA内存基地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;     //DMA的转换模式是SRC模式,就是从外设向内存中搬运,
  DMA_InitStructure.DMA_BufferSize = 1;     //DMA缓存大小,1个
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //接收一次数据后,设备地址是否后移
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;    //接收一次数据后,目标内存地址是否后移--重要概念,用来采集多个数据的
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;   //转换结果的数据大小
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  //DMA搬运的数据尺寸,注意ADC是12位的,HalfWord就是16位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;    //转换模式,循环缓存模式,常用,M2M果果开启了,这个模式失效
  DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA优先级,高
  DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;     //M2M模式禁止,memory to memory,这里暂时用不上
  DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  
  /* Enable DMA1 channel1 */
  DMA_Cmd(DMA1_Channel1, ENABLE);
  /* ADC1 configuration ------------------------------------------------------*/
  ADC_DeInit(ADC1);     //开启ADC1
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;//只是用了一个通道
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;   //连续转换模式开启
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   //ADC外部触发开关,关闭
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //对齐方式,ADC结果是12位的,显然有个对齐左边还是右边的问题。一般是右对齐
  ADC_InitStructure.ADC_NbrOfChannel = 1;    //开启通道数,1个
  ADC_Init(ADC1, &ADC_InitStructure);
  /* ADC1 regular channel8 configuration */
  ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5); //Configures ADC1 Channel10 as: first converted channel with an 55.5 cycles sample time  
   //规则组通道设置,关键函数 转换器ADC1,选择哪个通道channel,规则采样顺序,1代表规则通道第1个(1到16),最后一个参数是转换时间,越长越准越稳定
  //总转换时间=采样时间+12.5个周期=80个周期=10us
  /* Enable ADC1 DMA */
  ADC_DMACmd(ADC1, ENABLE);  //ADC命令,和DMA关联。
  
  /* Enable ADC1 */
  ADC_Cmd(ADC1, ENABLE);    //开启ADC1

  /* Enable ADC1 reset calibaration register */   
  ADC_ResetCalibration(ADC1);   //校准 寄存器复位

  /* Check the end of ADC1 reset calibration register */
  while(ADC_GetResetCalibrationStatus(ADC1));  //等待校准寄存器复位完成

  /* Start ADC1 calibaration */
  ADC_StartCalibration(ADC1);  //开始校准
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));  //等待校准完成
     
  /* Start ADC1 Software Conversion */
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);    //连续转换开始,从选择开始,MCU可以不用管了,ADC将通过DMA不断刷新

  while (1)
  {   
     AD_value= ADC_filter();
   Delay(Tim_1s);
  
   if (uart_flag1 == 1)
           {
               uart_flag1 = 0;
                       for(j1=0;j1<8;j1++)
                       {
                           USART_SendData(USART2, RX_dat1[j1]);
                         while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);  // 发送完成查询
           USART_ClearFlag(USART2,USART_FLAG_TC);
                                Delay(5545);
                        }      
               
   }     
}
}
void Delay(vu32 nCount)
{
  for(; nCount != 0; nCount--);
}

void RCC_Configuration(void)
{
   SystemInit();
#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
  /* ADCCLK = PCLK2/2 */
  RCC_ADCCLKConfig(RCC_PCLK2_Div2);
#else
  /* ADCCLK = PCLK2/4 */
  RCC_ADCCLKConfig(RCC_PCLK2_Div4);
#endif
   /* Enable DMA1 clock */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  //必须开时钟才能 使用起来 相应IO
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOC|RCC_APB2Periph_AFIO|RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
}
/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : Configures the different GPIO ports.
* Input          : None
* Output         : None
* Return         : None
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;      //选择引脚2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //输出频率最大50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //带上拉电阻输出
GPIO_Init(GPIOE,&GPIO_InitStructure);
GPIO_ResetBits(GPIOE,GPIO_Pin_2);               //将PE.2引脚设置为低电平输出

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_5; //选择引脚2 3 5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //选择输入模式为浮空输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;          //输出频率最大50MHz
GPIO_Init(GPIOC,&GPIO_InitStructure);                  //设置PC.2/PC.3/PC.5

*******************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
  /* Configure PC0 (ADC Channel10, ) as analog inputs */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  GPIO_Init(GPIOC, &GPIO_InitStructure);
/* Configure  PA2、PA9 as USART1 Tx*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9| GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;          //输出频率最大50MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure PA3、 PA10 as USART1 Rx*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10| GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*******************************************************************************
* Function Name  : NVIC_Configuration
* Description    : Configures the NVIC
* Input          : None
* Output         : None
* Return         : None
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);          //选择中断分组2
NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQChannel;     //选择中断通道2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //响应式中断优先级设置为0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;          //使能中断
NVIC_Init(&NVIC_InitStructure);
*******************************************************************************/
void NVIC_Configuration(void)
{
   NVIC_InitTypeDef NVIC_InitStructure;
   #ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM,0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH,0x0);
#endif
  
/* Enable the USART1 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

/* Enable the USART2 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
  }

/*******************************************************************************
* Function Name  : USART_Configuration
* Description    : Configures the USART1.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void USART_Configuration(void)
{
  USART_InitTypeDef USART_InitStructure;
//  USART_ClockInitTypeDef USART_ClockInitStructure;

  /* USART1 configuration ----------------------------------------------------*/
  /* USART1 configured as follow:
        - BaudRate = 115200 baud  
        - Word Length = 8 Bits
        - One Stop Bit
        - No parity
        - Receive and transmit enabled
        - Hardware flow control disabled (RTS and CTS signals)  
  */
  USART_InitStructure.USART_BaudRate =115200;
  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_ClockInitStructure.USART_Clock = USART_Clock_Disable;
// USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
//  USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
//  USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
  USART_Init(USART1, &USART_InitStructure);
  USART_Init(USART2, &USART_InitStructure);
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开接收中断
  USART_Init(USART2, &USART_InitStructure);
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);   //开接收中断
  /* Enable USART1,2 */
   USART_Cmd(USART1, ENABLE);
USART_Cmd(USART2, ENABLE);
}
//16ms finish a ADC detection
// return mv
uint32_t ADC_filter(void)
{
unsigned int result=0;
unsigned char m;
for(m=16;m>0;m--)
{
Delay(Tim_1ms);
//n=ADC_GetConversionValue(ADC1);
result += ADC_GetConversionValue(ADC1);    //返回最近一次ADCx规则组的转换结果Returns the ADC1 Master data value of the last converted channel

}
return (uint32_t)(((unsigned long)(result>>4))*3300>>12);  //  result/16  * 3300/12
}

  #ifdef DEBUG
  /*描述:当程序出错时,返回出错的文件名及在源程序中的行号
   输入:—file:指向文件名的指针
   —line:在源程序中的行号
   输出:无
   返回:无
   */
   void assert_failed(u8*file,u32 line)
   {
   while(1) {}
   }
#endif


中断函数

其中0xAA 0x78为一帧数据的开始,0xCC,0x33,0xC3,0x3C为一帧数据的结束,中间还有两个字节。

void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //检查相应的中断发生没
{

  
   RX_dat1[i1++] = USART_ReceiveData(USART1);
      
           if((RX_dat1[0]==0xAA)&&(RX_dat1[1]==0x78)&&(RX_dat1[4]==0xCC)&&(RX_dat1[5]==0x33)&&(RX_dat1[6]==0xC3)&&(RX_dat1[7]==0x3C))
     {
        i1=0;
    uart_flag1 = 1;
     }  
  
   
   USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除相应的中断标志位  
}
}



沙发
fymok|  楼主 | 2011-9-26 14:41 | 只看该作者
木人回答

使用特权

评论回复
板凳
香水城| | 2011-9-26 14:56 | 只看该作者
一般让人帮助程序中挑错的帖子都很少有人愿意回答,谁有这么多时间去看你的程序呢?

你这个问题显然是程序逻辑的问题,还是自己好好的检查一下吧。

使用特权

评论回复
地板
baidudz| | 2011-9-26 18:52 | 只看该作者
程序太长了,估计很少有人看完

使用特权

评论回复
5
xuepiaojiangu| | 2011-9-26 19:43 | 只看该作者
本帖最后由 xuepiaojiangu 于 2011-9-26 19:48 编辑

你的i1师在哪里定义的呢?没有看到定义。是全局变量吗?看着程序的意思,i1是个全局变量诶。知道满足你的条件之后,在中断中将其置为0,是吗?有没有试试给这个清0换个地方呢?比如挪到主函数中试试。

使用特权

评论回复
6
fymok|  楼主 | 2011-9-26 20:43 | 只看该作者
5# xuepiaojiangu

你说的对,i1是全局变量。我把i1挪到主函数中了,问题还是出现。


谢谢你  看完程序  然后回答

使用特权

评论回复
7
fymok|  楼主 | 2011-9-26 20:44 | 只看该作者
4# baidudz

程序是长了点,都是一些配置。

我自己查了一天了,不知道什么原因,希望有人指导一下

使用特权

评论回复
8
bobo5650| | 2011-9-27 08:32 | 只看该作者
RX_dat1[i1++] = USART_ReceiveData(USART1);
      
           if((RX_dat1[0]==0xAA)&&(RX_dat1[1]==0x78)&&(RX_dat1[4]==0xCC)&&(RX_dat1[5]==0x33)&&(RX_dat1[6]==0xC3)&&(RX_dat1[7]==0x3C))
     {
        i1=0;
    uart_flag1 = 1;
     }  

第一次处理完之后有清理缓存RX_dat1吗?
如果没有清理肯定有问题,并且问题会符合你的描述。

使用特权

评论回复
9
fymok|  楼主 | 2011-9-27 08:50 | 只看该作者
8# bobo5650


好像没清缓存,谢谢你啊  我看看去

使用特权

评论回复
10
fymok|  楼主 | 2011-9-27 08:55 | 只看该作者
如果在中断程序里加上下述语句,则每次接收到的数都一样,没变化

        //溢出-如果发生溢出需要先读SR,再读DR寄存器则可清除不断入中断的问题[牛人说要这样]
                if(USART_GetFlagStatus(USART1,USART_FLAG_ORE)==SET)
        {
                USART_ClearFlag(USART1,USART_FLAG_ORE); //读SR其实就是清除标志
                 USART_ReceiveData(USART1);//读DR
        }

使用特权

评论回复
11
fymok|  楼主 | 2011-9-27 11:40 | 只看该作者
已经验证,此语句逻辑有错

if((RX_dat1[0]==0xAA)&&(RX_dat1[1]==0x78)&&(RX_dat1[4]==0xCC)&&(RX_dat1[5]==0x33)&&(RX_dat1[6]==0xC3)&&(RX_dat1[7]==0x3C))

使用特权

评论回复
12
woyaochenggong| | 2011-9-27 11:47 | 只看该作者
缺少配置吧

使用特权

评论回复
13
fymok|  楼主 | 2011-9-27 12:16 | 只看该作者
12# woyaochenggong
逻辑有错  改写成下面的语句就行了


RX_dat1[i1++] = USART_ReceiveData(USART1);


if(i1==8)


{

i1=0;

if((RX_dat1[0]==0xAA)&&(RX_dat1[1]==0x78)&&(RX_dat1[4]==0xCC)&&(RX_dat1[5]==0x33)&&(RX_dat1[6]==0xC3)&&(RX_dat1[7]==0x3C))

   uart_flag1 = 1;



}

使用特权

评论回复
14
woyaochenggong| | 2011-9-29 08:36 | 只看该作者
看了几下,好累呀,

使用特权

评论回复
15
video_vb| | 2011-10-8 17:03 | 只看该作者
13# fymok
还会有问题,当通讯错误时少接收一个字节或者多一个字节后,就无法再通讯了.

使用特权

评论回复
16
bobo5650| | 2011-10-9 18:29 | 只看该作者
你的程序本来就没有容错机制来的
从你的代码看你是用0x CC 33 C3 3C这样一个序列做结束,那么你判断一个包结束的时候,很明显应该用检查已接收的最后4个字节是不是这个序列,但是你的程序判断的是第5到第8个字节,只要你的数据区多一个字节或者少一个字节,你的判断就错了。

使用特权

评论回复
17
yinyangdianzi| | 2011-10-10 10:48 | 只看该作者
加油

使用特权

评论回复
18
zyw567| | 2011-10-11 17:14 | 只看该作者
LZ加油

使用特权

评论回复
19
zyw567| | 2011-10-11 17:15 | 只看该作者
LZ加油

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

40

帖子

0

粉丝