大家好,我单片机用的是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;j10;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); //清除相应的中断标志位 } } |
RE:【奇怪问题】USART通信第一次正常,第二次死机
RE:【奇怪问题】USART通信第一次正常,第二次死机
2、接受完以后一定要清除接受缓冲区的数据,不然,下次进来肯定是正确的。我认为这个可能性是最大的。
RE:【奇怪问题】USART通信第一次正常,第二次死机
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))
RE:【奇怪问题】USART通信第一次正常,第二次死机
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))
RE:【奇怪问题】USART通信第一次正常,第二次死机
1、通讯速率过快会引起误码的增加,如果接收过程中产生了误码则i1变量就不会清零,从而引起接收缓冲区溢出而死机;
2、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;
}
这段代码貌似很短,但实际占用的时间应该会很大,在中断内部采用此种方式时会导致接收数据的丢失,如果上位机二帧数据发送时间间隔过短,会导致第二帧接收到数据头丢失,从而使i1不能清零,导致死机
RE:【奇怪问题】USART通信第一次正常,第二次死机
不过首先要分析下,流程是否有问题,然后再分析程序。