我调在个485通信调了好久了,一直解决不了收发不定长数据问题,大佬帮忙看下,我把发送函数中的第一个 while( USART_GetFlagStatus( UART4, USART_FLAG_TC ) == RESET );加上就会一直卡死在这一句,如果不加在一句就只能收到不定长数据的最后一个字符,不管字符长度是多少都只能收到最后一个。(用的STM32的F103RE的芯片)
void uart4_Send( u8 *buf, u16 len )
{
u16 t;
CS_485_tx;
for( t = 0; t < len; t++ ) //循环发送数据
{
// while( USART_GetFlagStatus( UART4, USART_FLAG_TC ) == RESET );
USART_SendData( UART4, buf[t] );
}
while( USART_GetFlagStatus( UART4, USART_FLAG_TC ) == RESET );
CS_485_rx;
}
具体代码如下:
点C文件;
u8 rec_buff[UART4_REC_LEN] = {0};
u16 uart4_rec_cnt = 0; //串口接收数据长度
u8 data_backup[UART4_REC_LEN] = {0}; //数据备份
u16 dataLen_backup = 0; //长度备份
u8 receiveOK_flag = 0; //接收完成标志位
/*
空闲中断是什么意思呢?
指的是当总线接收数据时,一旦数据流断了,此时总线没有接收传输,处于空闲状态,IDLE就会置1,产生空闲中断;又有数据发送时,IDLE位就会置0;
注意:置1之后它不会自动清0,也不会因为状态位是1而一直产生中断,它只有0跳变到1时才会产生,也可以理解为上升沿触发。
所以,为确保下次空闲中断正常进行,需要在中断服务函数发送任意数据来清除标志位。
*/
/***********************************************************************/
//*******函数名:rs485_init()
//*******用 途:与主板通讯
//*******说 明:传输控制和检测数据给主板
/***********************************************************************/
void rs485_init()
{
GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量,用来初始化GPIO
USART_InitTypeDef USART_InitStructure; //串口结构体定义
NVIC_InitTypeDef NVIC_InitStructure; //中断结构体定义
//打开时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOD|RCC_APB2Periph_AFIO,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART4,ENABLE);
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);
// RCC_APB1PeriphClockCmd(RCC_APB1Periph_UART5,ENABLE);
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10; //TX-485 //串口输出PC10
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出
// GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure); /* 初始化串口输入IO */
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_15; //CS-485
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11; //RX-485 //串口输入PC11
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //模拟输入
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure); /* 初始化GPIO */
USART_InitStructure.USART_BaudRate = 9600; //波特率设置为9600 //波特率
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_Tx | USART_Mode_Rx; //开启发送和接受模式
USART_Init(UART4, &USART_InitStructure); /* 初始化USART4 */
USART_Cmd(UART4,ENABLE);
USART_ITConfig(UART4,USART_IT_RXNE,ENABLE); //使能或者失能指定的USART中断 接收中断
USART_ITConfig(UART4,USART_IT_IDLE,ENABLE); //使能或者失能指定的USART中断 空闲中断
USART_ClearFlag(UART4,USART_FLAG_TC); //清除USARTx的待处理标志位
/* 设置NVIC参数 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = UART4_IRQn; //打开USART2的全局中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //抢占优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //响应优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能
NVIC_Init(&NVIC_InitStructure);
CS_485_rx;
}
/*
void uart2_init( u16 baud )
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART2, ENABLE );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //推挽复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init( &NVIC_InitStructure );
USART_InitStructure.USART_BaudRate = baud;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init( USART2, &USART_InitStructure );
USART_ITConfig( USART2, USART_IT_IDLE, ENABLE ); //使能串口空闲中断
USART_ITConfig( USART2, USART_IT_RXNE, ENABLE ); //使能串口RXNE接收中断
USART_Cmd( USART2, ENABLE ); //使能串口2
}
*/
//发送len个字节
//buf:发送区首地址
//len:发送的字节数
void uart4_Send( u8 *buf, u16 len )
{
u16 t;
CS_485_tx;
for( t = 0; t < len; t++ ) //循环发送数据
{
while( USART_GetFlagStatus( UART4, USART_FLAG_TC ) == RESET );
USART_SendData( UART4, buf[t] );
}
while( USART_GetFlagStatus( UART4, USART_FLAG_TC ) == RESET );
CS_485_rx;
}
//备份接收到的数据
void copy_data( u8 *buf, u16 len )
{
u16 t;
dataLen_backup = len; //保存数据长度
for( t = 0; t < len; t++ )
{
data_backup[t] = buf[t]; //备份接收到的数据,防止在处理数据过程中接收到新数据,将旧数据覆盖掉。
}
}
//利用空闲中断接收串口不定长数据
//RXNE中断和IDLE中断的区别?
//当接收到1个字节,就会产生RXNE中断,当接收到一帧数据,就会产生IDLE中断。比如给单片机一次性发送了8个字节,就会产生8次RXNE中断,1次IDLE中断。
void UART4_IRQHandler( void )
{
u8 tem = 0;
if( USART_GetITStatus( UART4, USART_IT_RXNE ) != RESET ) //接收中断 接收到一个字节产生一次中断
{
tem = USART_ReceiveData( UART4 ); //读取数据,可以自动将中断标志位RXNE清零
rec_buff[uart4_rec_cnt++] = tem; //存储接收到的数据
}
if( USART_GetITStatus( UART4, USART_IT_IDLE ) != RESET ) //空闲中断 接收到一帧数据 产生一次中断
{
tem = UART4->SR; //读取SR寄存器
tem = UART4->DR; //读取DR寄存器 (先读USART_SR,然后读USART_DR可以清除空闲中断标志位IDLE)
//uart2_Send( rec_buff, uart2_rec_cnt ); //一帧数据接收完毕,将接收到的数据发送出去
copy_data( rec_buff, uart4_rec_cnt ); //备份数据
receiveOK_flag = 1; //接收完成标志位置位
uart4_rec_cnt = 0; //接收数据长度清零
}
}
main文件;
rs485_init();
while(1)
{
if( receiveOK_flag ==1 ) //一帧数据接收完成后开始处理数据
{
receiveOK_flag = 0;
uart4_Send( data_backup, dataLen_backup ); //发送数据
memset( data_backup, 0, sizeof( data_backup ) ); //清空备份数组
CS_485_rx;
}