OpenEdv-开源电子网

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

f103c8t6,TIM2 3 4同时使用,出现问题,求助!!!

[复制链接]

6

主题

17

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2019-10-17
在线时间
16 小时
发表于 2020-3-28 14:23:14 | 显示全部楼层 |阅读模式
1金钱
各位大佬好。
用c8t6的串口2加上485,用定时器4来定时1s,前500ms发送,后500ms来处理485传感器响应的数据。定时器3来判断返回的数据是否接收完毕。
以上 程序都是正常运行的,并且能在显示屏上显示出来。

之后,我又在串口1上配置了NB模块,采用DMA通道4发送,串口一接收中断的方式。同时用TIM2来判断串口1的接收数据是否完毕。

但是!添加上之后,,程序就不能正常运行了,直接进不到主函数里面。

但是 只要把485传感器断电之后,程序又可以进到主函数了。

请问 各位大佬,有知道咋回事的吗? 困了我一个周了。。。

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

使用道具 举报

6

主题

17

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2019-10-17
在线时间
16 小时
 楼主| 发表于 2020-3-28 14:25:12 | 显示全部楼层
我贴一下 串口一的代码(同时配置了TIM2)

#include "delay.h"
#include "usart.h"
#include "stdarg.h"                  
#include "stdio.h"                  
#include "string.h"          
                                                                  
//////////////////////////////////////////////////////////////////////////////////           

//串口发送缓存区        
__align(8) u8 USART1_TX_BUF[USART1_MAX_SEND_LEN];         //发送缓冲,最大USART2_MAX_SEND_LEN字节
#ifdef USART1_RX_EN                                                                   //如果使能了接收             
//串口接收缓存区        
u8 USART1_RX_BUF[USART1_MAX_RECV_LEN];                                 //接收缓冲,最大USART2_MAX_RECV_LEN个字节.



//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
u16 USART1_RX_STA=0;  


void USART1_IRQHandler(void)
{
        u8 res;            
        if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)//接收到数据
        {         

        res =USART_ReceiveData(USART1);               
                if(USART1_RX_STA<USART1_MAX_RECV_LEN)                //还可以接收数据
                {
                        TIM_SetCounter(TIM2,0);//计数器清空                                         
                        if(USART1_RX_STA==0)TIM2_Set(1);                 //使能定时器4的中断
                        USART1_RX_BUF[USART1_RX_STA++]=res;                //记录接收到的值         
                }else
                {
                        USART1_RX_STA|=1<<15;                                        //强制标记接收完成
                }
        }                                                                                           
}   



//初始化IO 串口2
//pclk1CLK1时钟频率(Mhz)
//bound:波特率          
void USART1_Init(u32 bound)
{  

        NVIC_InitTypeDef NVIC_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);        // GPIOA时钟
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

        USART_DeInit(USART1);  //复位串口2
                 //USART2_TX   PA.2
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.2
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
   
    //USART2_RX          PA.3
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PA3
       
        USART_InitStructure.USART_BaudRate = bound;//一般设置为9600;
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        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_Init(USART1, &USART_InitStructure); //初始化串口        2
  
        //波特率设置
//        USART2->BRR=(pclk1*1000000)/(bound);// 波特率设置         
        //USART2->CR1|=0X200C;          //1位停止,无校验位.
        USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);          //使能串口2的DMA发送
        UART_DMA_Config(DMA1_Channel4,(u32)&USART1->DR,(u32)USART1_TX_BUF);//DMA1通道7,外设为串口2,存储器为USART2_TX_BUF
        USART_Cmd(USART1, ENABLE);                    //使能串口
       
#ifdef USART1_RX_EN                          //如果使能了接收
        //使能接收中断
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启中断   
       
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
        TIM2_Init(999,7199);                //10ms中断
        USART1_RX_STA=0;                //清零
        TIM2_Set(0);                        //关闭定时器4
#endif                

}
//串口2,printf 函数
//确保一次发送数据不超过USART2_MAX_SEND_LEN字节
void u1_printf(char* fmt,...)  
{  
        va_list ap;
        va_start(ap,fmt);
        vsprintf((char*)USART1_TX_BUF,fmt,ap);
        va_end(ap);
        while(DMA_GetCurrDataCounter(DMA1_Channel4)!=0);        //等待通道7传输完成   
        UART_DMA_Enable(DMA1_Channel4,strlen((const char*)USART1_TX_BUF));         //通过dma发送出去
}
//定时器4中断服务程序                    
void TIM2_IRQHandler(void)
{        
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//是更新中断
        {                                   
                USART1_RX_STA|=1<<15;        //标记接收完成
                TIM_ClearITPendingBit(TIM2, TIM_IT_Update);  //清除TIMx更新中断标志   
                TIM2_Set(0);                        //关闭TIM4  
        }            
}
//设置TIM4的开关
//sta:0,关闭;1,开启;
void TIM2_Set(u8 sta)
{
        if(sta)
        {
      
                TIM_SetCounter(TIM2,0);//计数器清空
                TIM_Cmd(TIM2, ENABLE);  //使能TIMx       
        }else TIM_Cmd(TIM2, DISABLE);//关闭定时器4          
}
//通用定时器中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数                 
void TIM2_Init(u16 arr,u16 psc)
{       
        NVIC_InitTypeDef NVIC_InitStructure;
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //时钟使能//TIM4时钟使能   
       
        //定时器TIM3初始化
        TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值       
        TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位

        TIM_ITConfig(TIM1,TIM_IT_Update,ENABLE ); //使能指定的TIM4中断,允许更新中断

                   
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器
       
}
#endif                 
///////////////////////////////////////USART2 DMA发送配置部分//////////////////////////////////                               
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHxMA通道CHx
//cpar:外设地址
//cmar:存储器地址   
void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar)
{
        DMA_InitTypeDef DMA_InitStructure;
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //使能DMA传输
  DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值
        DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设ADC基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;  //数据传输方向,从内存读取发送到外设
        DMA_InitStructure.DMA_BufferSize = 0;  //DMA通道的DMA缓存的大小
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;  //数据宽度为8位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; //数据宽度为8位
        DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器       
}
//开启一次DMA传输
void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len)
{
        DMA_Cmd(DMA_CHx, DISABLE );  //关闭 指示的通道        
        DMA_SetCurrDataCounter(DMA_CHx,len);//DMA通道的DMA缓存的大小       
        DMA_Cmd(DMA_CHx, ENABLE);           //开启DMA传输
}          
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////                                                                          





















回复

使用道具 举报

6

主题

17

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2019-10-17
在线时间
16 小时
 楼主| 发表于 2020-3-28 14:26:36 | 显示全部楼层
串口二的配置代码(同时配置TIM3 TIM4)

//初始化IO 串口2
void RS485_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD,ENABLE);//使能GPIOA,D时钟
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
        
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;//PA2
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
        GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        GPIO_SetBits(GPIOA,GPIO_Pin_2);///PA2  默认高电平
        
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3;//PA3(RX)输入上拉
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;   //浮空输入
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        
        GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;//修改PG9(RE/DE)通用推挽输出->PD7(RE/DE)通用推挽输出//////////////////////////////////////////////////////////////////////
        GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//普通推挽输出
        GPIO_Init(GPIOA,&GPIO_InitStructure);
        GPIO_ResetBits(GPIOA,GPIO_Pin_1);//默认接收状态
        
        USART_DeInit(USART2);//复位串口2
        USART_InitStructure.USART_BaudRate=RS485_Baudrate;//波特率设置 9600
        USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;//无硬件数据流控制
        USART_InitStructure.USART_WordLength=USART_WordLength_8b;//8位数据长度
        USART_InitStructure.USART_StopBits=USART_StopBits_1;//一个停止位
        USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;//收发模式
        switch(RS485_Parity)
        {
                case 0:USART_InitStructure.USART_Parity=USART_Parity_No;break;//无校验
                case 1:USART_InitStructure.USART_Parity=USART_Parity_Odd;break;//奇校验
                case 2:USART_InitStructure.USART_Parity=USART_Parity_Even;break;//偶校验
        }
        USART_Init(USART2,&USART_InitStructure);//初始化串口
        
        USART_ClearITPendingBit(USART2,USART_IT_RXNE);//有没有好像都可以
        USART_ITConfig(USART2,USART_IT_RXNE,ENABLE);//开启中断
        
        NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn;//使能串口2中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//先占优先级3级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority=2; //从优先级3级
        NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;//使能外部中断通道
        NVIC_Init(&NVIC_InitStructure);//根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
        
        USART_Cmd(USART2,ENABLE);//使能串口2
        RS485_TX_EN=1;//默认为发送模式       485模式控制.0,接收;1,发送.
        
        Timer3_Init();//定时器7初始化,用于监视空闲时间
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
//定时器4初始化
//定时1s进行通讯,分2步,前500ms进行发送功能,后500ms处理从机返回的数据
void Timer4_enable(u16 arr)                   //TIM4使能
{
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); //时钟使能       
        TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值         计数到5000为500ms
        TIM_TimeBaseStructure.TIM_Prescaler = 7199; //设置用来作为TIMx时钟频率除数的预分频值  10Khz的计数频率  
        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

        TIM_ITConfig(  //使能或者失能指定的TIM中断
                TIM4, //TIM2
                TIM_IT_Update  |  //TIM 中断源
                TIM_IT_Trigger,   //TIM 触发中断源
                ENABLE  //使能
                );

        NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;  //TIM3中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  //先占优先级0级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;  //从优先级3级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器

        TIM_Cmd(TIM4, ENABLE);  //使能TIMx外设                                                         
}

void Timer4_disable (void)                                           //TIM4失能
{
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, DISABLE); //时钟失能
        TIM_ITConfig(TIM4, TIM_IT_Update | TIM_IT_Trigger,DISABLE );
        TIM_Cmd(TIM4, DISABLE);  //失能TIMx外设
}
///////////////////////////////////////////////////////////////////////////////////////////////
//定时器7初始化---功能:判断从机返回的数据是否接受完成

void Timer3_Init(void)
{
        TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //TIM7时钟使能

        //TIM7初始化设置
        TIM_TimeBaseStructure.TIM_Period = RS485_Frame_Distance*10; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值
        TIM_TimeBaseStructure.TIM_Prescaler =7199; //设置用来作为TIMx时钟频率除数的预分频值 设置计数频率为10kHz
        TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式
        TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位

        TIM_ITConfig( TIM3, TIM_IT_Update, ENABLE );//TIM7 允许更新中断

        //TIM7中断分组配置
        NVIC_InitStructure.NVIC_IRQChannel =TIM3_IRQn;  //TIM7中断
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  //先占优先级2级    先占优先级值越小,优先级越高
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //从优先级3级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道被使能
        NVIC_Init(&NVIC_InitStructure);  //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器                                                                  
}

/////////////////////////////////////////////////////////////////////////////////////
void USART2_IRQHandler(void)//串口2中断服务程序
{
          
        u8 res;
        if(USART_GetITStatus(USART2,USART_IT_RXNE)!=RESET)
        {
                res=USART_ReceiveData(USART2); //读接收到的字节,同时相关标志自动清除
                                if(RS485_RX_CNT<200)//还可以接受数据
                {
                        RS485_RX_BUFF[RS485_RX_CNT]=res;
                        RS485_RX_CNT++;
                        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除定时器溢出中断
                        TIM_SetCounter(TIM3,0);//当接收到一个新的字节,将定时器7复位为0,重新计时(相当于喂狗)
                        TIM_Cmd(TIM3,ENABLE);//开始计时
                }
        }
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
void TIM4_IRQHandler(void)   //TIM4中断
{
        if (TIM_GetITStatus(TIM4,TIM_IT_Update) == SET) //检查指定的TIM中断发生与否:TIM 中断源
        {
                TIM_ClearITPendingBit(TIM4, TIM_IT_Update  );  //清除TIMx的中断待处理位:TIM 中断源 ;
                modbus_rtu();
                j++;
                j=j%2;
                if(j==1){n++;n=n%2;}
//                printf("n=%d",n);
        }
}

//用定时器7判断接收空闲时间,当空闲时间大于指定时间,认为一帧结束
//定时器7中断服务程序         
void TIM3_IRQHandler(void)
{                                                                  
        if(TIM_GetITStatus(TIM3,TIM_IT_Update)!=RESET)
        {
                TIM_ClearITPendingBit(TIM3,TIM_IT_Update);//清除中断标志
                TIM_Cmd(TIM3,DISABLE);//停止定时器
                RS485_TX_EN=1;//停止接收,切换为发送状态     485模式控制.0,接收;1,发送.
                RS485_RxFlag=1;//置位帧结束标记
        }
}
回复

使用道具 举报

15

主题

1061

帖子

0

精华

资深版主

Rank: 8Rank: 8

积分
3625
金钱
3625
注册时间
2019-8-14
在线时间
1054 小时
发表于 2020-3-28 15:03:44 | 显示全部楼层
帮顶   
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165516
金钱
165516
注册时间
2010-12-1
在线时间
2116 小时
发表于 2020-3-29 00:57:43 | 显示全部楼层
仿真找问题
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-5-24 00:14

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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