找回密码
 立即注册
查看: 59|回复: 3

一个DMA_ADC导致的程序跑飞及死机的问题 | <= 40MHz

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:7
  • 最近打卡:2026-02-23 11:11:05
已绑定手机

5

主题

4

回帖

53

积分

注册会员

积分
53
发表于 2026-2-19 23:38:04 | 显示全部楼层 |阅读模式
目前遇到的问题:加入DMA_ADC后串口过段时间(大约3~5分钟不等)就会不能收发数据,另外会随机的写modbus寄存器数组的信息,去掉DMA_ADC的函数调用后恢复正常。    这期间我设置过堆栈,将堆栈空间更改为IDATALEN        EQU     7FH,会好一些,但更改其他数值无太大影响。   补充说明:串口2  串口3 串口4四路串口做RS485独立通讯,time0:做100us中断并将中断优先级开到最高(作为串口接收超时检测),串口优先级开到较高。  DMA接收中断优先级开到最低。        希望各位大神可以帮忙分析下原因,已经卡柱好几天,找不到解决方法。


以下是相关代码
STARTUP.A51
$NOMOD51
;------------------------------------------------------------------------------
;  This file is part of the C51 Compiler package
;  Copyright (c) 1988-2005 Keil Elektronik GmbH and Keil Software, Inc.
;  Version 8.01
;
;  *** <<< Use Configuration Wizard in Context Menu >>> ***
;------------------------------------------------------------------------------
;  STARTUP.A51:  This code is executed after processor reset.
;
;  To translate this file use A51 with the following invocation:
;
;     A51 STARTUP.A51
;
;  To link the modified STARTUP.OBJ file to your application use the following
;  Lx51 invocation:
;
;     Lx51 your object file list, STARTUP.OBJ  controls
;
;------------------------------------------------------------------------------
;
;  User-defined <h> Power-On Initialization of Memory
;
;  With the following EQU statements the initialization of memory
;  at processor reset can be defined:
;
; <o> IDATALEN: IDATA memory size <0x0-0x100>
;     <i> Note: The absolute start-address of IDATA memory is always 0
;     <i>       The IDATA space overlaps physically the DATA and BIT areas.
IDATALEN        EQU     7FH
;
; <o> XDATASTART: XDATA memory start address <0x0-0xFFFF>
;     <i> The absolute start address of XDATA memory
XDATASTART      EQU     0     
;
; <o> XDATALEN: XDATA memory size <0x0-0xFFFF>
;     <i> The length of XDATA memory in bytes.
XDATALEN        EQU     0x2000      
;
; <o> PDATASTART: PDATA memory start address <0x0-0xFFFF>
;     <i> The absolute start address of PDATA memory
PDATASTART      EQU     0H
;
; <o> PDATALEN: PDATA memory size <0x0-0xFF>
;     <i> The length of PDATA memory in bytes.
PDATALEN        EQU     0H
;
;</h>
;------------------------------------------------------------------------------
;
;<h> Reentrant Stack Initialization
;
;  The following EQU statements define the stack pointer for reentrant
;  functions and initialized it:
;
; <h> Stack Space for reentrant functions in the SMALL model.
;  <q> IBPSTACK: Enable SMALL model reentrant stack
;     <i> Stack space for reentrant functions in the SMALL model.
IBPSTACK        EQU     0       ; set to 1 if small reentrant is used.
;  <o> IBPSTACKTOP: End address of SMALL model stack <0x0-0xFF>
;     <i> Set the top of the stack to the highest location.
IBPSTACKTOP     EQU     0xFF +1     ; default 0FFH+1  
; </h>
;
; <h> Stack Space for reentrant functions in the LARGE model.      
;  <q> XBPSTACK: Enable LARGE model reentrant stack
;     <i> Stack space for reentrant functions in the LARGE model.
XBPSTACK        EQU     0       ; set to 1 if large reentrant is used.
;  <o> XBPSTACKTOP: End address of LARGE model stack <0x0-0xFFFF>
;     <i> Set the top of the stack to the highest location.
XBPSTACKTOP     EQU     0x1FFF +1   ; default 0FFFFH+1
; </h>
;
; <h> Stack Space for reentrant functions in the COMPACT model.   
;  <q> PBPSTACK: Enable COMPACT model reentrant stack
;     <i> Stack space for reentrant functions in the COMPACT model.
PBPSTACK        EQU     0       ; set to 1 if compact reentrant is used.
;
;   <o> PBPSTACKTOP: End address of COMPACT model stack <0x0-0xFFFF>
;     <i> Set the top of the stack to the highest location.
PBPSTACKTOP     EQU     0xFF00 +1     ; default 0FFH+1  
; </h>
;</h>
;------------------------------------------------------------------------------
;
;  Memory Page for Using the Compact Model with 64 KByte xdata RAM
;  <e>Compact Model Page Definition
;
;  <i>Define the XDATA page used for PDATA variables.
;  <i>PPAGE must conform with the PPAGE set in the linker invocation.
;
; Enable pdata memory page initalization
PPAGEENABLE     EQU     0       ; set to 1 if pdata object are used.
;
; <o> PPAGE number <0x0-0xFF>
; <i> uppermost 256-byte address of the page used for PDATA variables.
PPAGE           EQU     0
;
; <o> SFR address which supplies uppermost address byte <0x0-0xFF>
; <i> most 8051 variants use P2 as uppermost address byte
PPAGE_SFR       DATA    0A0H
;
; </e>
;------------------------------------------------------------------------------


; Standard SFR Symbols
ACC     DATA    0E0H
B       DATA    0F0H
SP      DATA    81H
DPL     DATA    82H
DPH     DATA    83H


                NAME    ?C_STARTUP




?C_C51STARTUP   SEGMENT   CODE
?STACK          SEGMENT   IDATA


                RSEG    ?STACK
                DS      1


                EXTRN CODE (?C_START)
                PUBLIC  ?C_STARTUP


                CSEG    AT      0
?C_STARTUP:     LJMP    STARTUP1


                RSEG    ?C_C51STARTUP


STARTUP1:


IF IDATALEN <> 0
                MOV     R0,#IDATALEN - 1
                CLR     A
IDATALOOP:      MOV     @R0,A
                DJNZ    R0,IDATALOOP
ENDIF


IF XDATALEN <> 0
                MOV     DPTR,#XDATASTART
                MOV     R7,#LOW (XDATALEN)
  IF (LOW (XDATALEN)) <> 0
                MOV     R6,#(HIGH (XDATALEN)) +1
  ELSE
                MOV     R6,#HIGH (XDATALEN)
  ENDIF
                CLR     A
XDATALOOP:      MOVX    @DPTR,A
                INC     DPTR
                DJNZ    R7,XDATALOOP
                DJNZ    R6,XDATALOOP
ENDIF


IF PPAGEENABLE <> 0
                MOV     PPAGE_SFR,#PPAGE
ENDIF


IF PDATALEN <> 0
                MOV     R0,#LOW (PDATASTART)
                MOV     R7,#LOW (PDATALEN)
                CLR     A
PDATALOOP:      MOVX    @R0,A
                INC     R0
                DJNZ    R7,PDATALOOP
ENDIF


IF IBPSTACK <> 0
EXTRN DATA (?C_IBP)


                MOV     ?C_IBP,#LOW IBPSTACKTOP
ENDIF


IF XBPSTACK <> 0
EXTRN DATA (?C_XBP)


                MOV     ?C_XBP,#HIGH XBPSTACKTOP
                MOV     ?C_XBP+1,#LOW XBPSTACKTOP
ENDIF


IF PBPSTACK <> 0
EXTRN DATA (?C_PBP)
                MOV     ?C_PBP,#LOW PBPSTACKTOP
ENDIF


                MOV     SP,#?STACK-1


; This code is required if you use L51_BANK.A51 with Banking Mode 4
;<h> Code Banking
; <q> Select Bank 0 for L51_BANK.A51 Mode 4
#if 0   
;     <i> Initialize bank mechanism to code bank 0 when using L51_BANK.A51 with Banking Mode 4.
EXTRN CODE (?B_SWITCH0)
                CALL    ?B_SWITCH0      ; init bank mechanism to code bank 0
#endif
;</h>
                LJMP    ?C_START


                END




ADC.H
#ifndef __ADC_H__
#define __ADC_H__


#include "driver.h"






#define CHANNEL_02 02          //宏定义通道号
#define CHANNEL_03 03          //宏定义通道号
#define CHANNEL_06 06          //宏定义通道号
#define CHANNEL_07 07          //宏定义通道号
#define CHANNEL_13 13          //宏定义通道号
#define CHANNEL_14 14          //宏定义通道号
#define CHANNEL_15 15          //宏定义内部参考电源通道号




#define RREF 33000             //宏定义参考电阻大小


#define SAMPLED_WAIT_TIME 2  //采样等待时间 ms


#define        ADC_SPEED        10                        /* 0~15, ADC转换时间(CPU时钟数) = (n+1)*32  ADCCFG */
#define        RES_FMT                (1<<5)        /* ADC结果格式 0: 左对齐, ADC_RES: D11 D10 D9 D8 D7 D6 D5 D4, ADC_RESL: D3 D2 D1 D0 0 0 0 0 */
                          /* ADCCFG     1: 右对齐, ADC_RES: 0 0 0 0 D11 D10 D9 D8, ADC_RESL: D7 D6 D5 D4 D3 D2 D1 D0 */


#define        ADC_CH                7                                        /* 1~16, ADC转换通道数, 需同步修改 DMA_ADC_CHSW 转换通道 */
#define ADC_DMA_CH_CONVERSION_NUM 16   //单通道采样次数
#define ADC_DMA_ABANDON_NUM 4          //采样数据舍去最低和最高位数
#define        ADC_DATA        18                                     /* 6~n, 每个通道ADC转换数据总数, 转换次数+2, 需同步修改 DMA_ADC_CFG2 转换次数 */  //转换10次
#define        DMA_ADDR        0x1400                           /* DMA数据存放地址 */


//#define MAGNIFICATION 50    //检测电路放大倍数宏定义




//#define ADC_TEMP_NUM  20                 //ADC数据暂存数据数量
//#define ADC_DATA_ABANDON_NUM 4           //ADC实时平均值去掉首位数
//#define ADC_DATA_OVERFLOW  20            //连续溢出次数


typedef struct adc_init{
        unsigned char channel;    //通道选择 占用四个字节  0~15代表16个通道 15是内部参考电压通道
        unsigned char resfmt;     //数据对其方式  占用一个字节 0为左对齐 1为右对齐
        unsigned char speed;      //ADC时钟配置   占用4个字节 0~15 代表1~16分频
        unsigned char cssetup;          //通道选择时间,即准备时间   占用一个字节  0: 1ADC个时钟 1:2ADC个时钟
        unsigned char smpduty;    //采样时间   占用5个字节 0~31  代表1~32个ADC时钟
        unsigned char cshold;            //保持时间   占用2个字节 0~3 代表 1~4个ADC时钟
        unsigned char cvtimesel;  //自动转换次数 占用三个字节 3~7 代表1/2/4/8/16此
}USER_ADC_INIT;


typedef struct adc{
//    unsigned short adc_buff[20];             //缓存ADC采集的数据
    unsigned char adc_daq_num;               //ADC数据采集次数
          unsigned char adc_daq_cnt;               //ADC数据采样计数
          unsigned char adc_sampling_ok;           //采样完成标志位
          unsigned char adc_remove_ht_num;         //adc滤波使用,ADC采集一组数据,从小到达排序后滤除首尾偏移量数据的数量
    unsigned long adc_sum;                   //adc累加和
          unsigned short voltage_data;              //用于存储电源电压的数据
    unsigned short adc_results;              //ADC最终计算结果
}ADC_DATA_PROCESSING;




extern unsigned short xdata dma_buffer[ADC_CH][ADC_DATA];
extern unsigned short sampled_wait_time_count;   //采样间隔时间计数


extern ADC_DATA_PROCESSING ADC_CHANNEL_02;
extern ADC_DATA_PROCESSING ADC_CHANNEL_03;
extern ADC_DATA_PROCESSING ADC_CHANNEL_06;
extern ADC_DATA_PROCESSING ADC_CHANNEL_07;
extern ADC_DATA_PROCESSING ADC_CHANNEL_13;
extern ADC_DATA_PROCESSING ADC_CHANNEL_14;






extern unsigned char dma_adc_ok;  //dma_adc采样完成标志位


void ADC_KC(unsigned char adc_in_type);  //切换通道函数






void user_adc_init_service();
void adc_service(unsigned char *adc_sampling_ok);
void adc_1ms();


#endif


ADC.C
#include "adc.h"
#include <string.h> // 必须包含memset头文件
#include <intrins.h>


#include "b3950_10k.h"




unsigned char user_channel_num = 0;  // 用户通道编号
unsigned char test_flag = 0;  //测试头文件


ADC_DATA_PROCESSING ADC_CHANNEL_15 = {0};
ADC_DATA_PROCESSING ADC_CHANNEL_02 = {0};
ADC_DATA_PROCESSING ADC_CHANNEL_03 = {0};
ADC_DATA_PROCESSING ADC_CHANNEL_06 = {0};
ADC_DATA_PROCESSING ADC_CHANNEL_07 = {0};
ADC_DATA_PROCESSING ADC_CHANNEL_13 = {0};
ADC_DATA_PROCESSING ADC_CHANNEL_14 = {0};


unsigned short xdata dma_buffer[ADC_CH][ADC_DATA] _at_ DMA_ADDR;
//unsigned short dma_buffer[ADC_CH][ADC_DATA] = {0};


unsigned char dma_adc_ok = 0;  //dma_adc采样完成标志位


unsigned short adc_vref = 0;  //内部参考电压MV






/***********************************************************/
// description: 用户ADC初始化函数
//* param {*}
//* return {*}
/***********************************************************/
void adc_star()
{
        ADC_CONTR |= (0x01 << 6);          //启动转化
}


/***********************************************************/
// description: 用户ADC切换通道
//* param {*}
//* return {*}  0~15代表通道0~15
/***********************************************************/
void adc_change_channel(unsigned char channel_id)
{
        unsigned char temp_uchar_data = 0;
        temp_uchar_data = ADC_CONTR;
        temp_uchar_data &= 0xF0;          //先清零通道选择位
        temp_uchar_data |= channel_id;    //赋值通道选择位
        ADC_CONTR = temp_uchar_data;      //赋值寄存器  
}


/***********************************************************/
// description:void adc_gpio_init()
//* param {*}
//* return {*}
/***********************************************************/
void adc_gpio_init()
{
        P5M0 &= ~(0x01 << 4);   
  P5M1 |=  (0x01 << 4);   //p5.4接收管脚高阻输入
        
        P1M0 &= ~(0x01 << 3);   
  P1M1 |=  (0x01 << 3);   //p1.3接收管脚高阻输入        
        
        P1M0 &= ~(0x01 << 7);   
  P1M1 |=  (0x01 << 7);   //p1.7接收管脚高阻输入
        
        P1M0 &= ~(0x01 << 6);   
  P1M1 |=  (0x01 << 6);   //p1.6接收管脚高阻输入        


        P0M0 &= ~(0x01 << 6);   
  P0M1 |=  (0x01 << 6);   //p0.6接收管脚高阻输入
        
        P0M0 &= ~(0x01 << 5);   
  P0M1 |=  (0x01 << 5);   //p0.5接收管脚高阻输入               
        
  P5M0 |=  (0x01 << 3);   
  P5M1 &= ~(0x01 << 3);   //p5.3为发送管脚推挽输出                        
        
  P0M0 |=  (0x01 << 7);   
  P0M1 &= ~(0x01 << 7);   //p0.7为发送管脚推挽输出               


  P1M0 |=  (0x01 << 4);   
  P1M1 &= ~(0x01 << 4);   //p1.4为发送管脚推挽输出                        
        
  P1M0 |=  (0x01 << 5);   
  P1M1 &= ~(0x01 << 5);   //p1.5为发送管脚推挽输出        


  CHANNEL01_RWT_CONTROL_GPIO = 0;
        CHANNEL01_SWT_CONTROL_GPIO = 0;
        CHANNEL02_RWT_CONTROL_GPIO = 0;
        CHANNEL02_SWT_CONTROL_GPIO = 0;  //初始化关闭检测通道        
        
}




/***********************************************************/
// description: ADC初始化库
//* param {*}
//* return {*}
/***********************************************************/


void s_adc_init(USER_ADC_INIT *adc)
{
        ADC_CONTR |= 0x80;                              //开启ADC电源
        ADC_CONTR &= 0xF0;                             //先清零到通道一全为0
        ADC_CONTR |= (adc -> channel);    //通道选择 占用四个字节  0~15代表16个通道 15是内部参考电压通道
        ADCCFG = 0;                       //先清零此寄存器
        ADCCFG |= (adc -> resfmt << 5);   //设置数据对其方式寄存器
        ADCCFG |= (adc -> speed);         //设置ADC时钟分频寄存器
        ADCTIM = 0;
        ADCTIM |= (adc -> cssetup << 7);   //设置通道选择时间寄存器        
        ADCTIM |= (adc -> smpduty);        //设置采样时间寄存器               
        ADCTIM |= (adc -> cshold << 5);    //设置保持时间寄存器        
        ADCEXCFG = 0;        
        ADCEXCFG |= (adc -> cvtimesel);       //设置自动转换次数寄存器        
}






/***********************************************************/
// description: adc_dma_star启动
//* param {*}
//* return {*}  rx_buff_add:接收数据的地址
/***********************************************************/


void adc_dma_star()
{
//        ADC_CONTR |= (0x01 << 6);          //启动转化
  DMA_ADC_CR |= (0x01 << 6);         //启动DMA_ADC功能        
}




/***********************************************************/
// description: ADC_DMA初始化库
//* param {*}
//* return {*}  rx_buff_add:接收数据的地址
/***********************************************************/


void s_adc_dma_init(unsigned short rx_buff_add)
{        
        DMA_ADC_STA = 0x00;
//        DMA_ADC_CFG |= (0x02 << 2);  //调高中断优先级
        DMA_ADC_RXAH = (unsigned char)(rx_buff_add >> 8);
        DMA_ADC_RXAL = (unsigned char)rx_buff_add;        
        DMA_ADC_CFG2 = 11;        //每个通道ADC转换次数:16次
        DMA_ADC_CHSW0 = 0;        //ADC通道使能寄存器 ADC7~ADC0
        DMA_ADC_CHSW1 = 0;        //ADC通道使能寄存器 ADC15~ADC8


        DMA_ADC_CHSW0 |= (0x01 << 2);        //ADC通道使能寄存器 ADC7~ADC0   //开启02通道
        DMA_ADC_CHSW0 |= (0x01 << 3);        //ADC通道使能寄存器 ADC15~ADC8  //开启03通道               
        DMA_ADC_CHSW0 |= (0x01 << 6);        //ADC通道使能寄存器 ADC7~ADC0   //开启06通道
        DMA_ADC_CHSW0 |= (0x01 << 7);        //ADC通道使能寄存器 ADC15~ADC8  //开启07通道        
        
        DMA_ADC_CHSW1 |= (0x01 << 5);        //ADC通道使能寄存器 ADC7~ADC0   //开启13通道
        DMA_ADC_CHSW1 |= (0x01 << 6);        //ADC通道使能寄存器 ADC15~ADC8  //开启14通道
        DMA_ADC_CHSW1 |= (0x01 << 7);        //ADC通道使能寄存器 ADC15~ADC8         //开启15通道
  DMA_ADC_CR |= (0x01 << 7);         //使能ADC_DMA功能
        DMA_ADC_CFG |= (0x01 << 7);  //使能中断
        
}






/***********************************************************/
// description: 用户ADC初始化函数
//* param {*}
//* return {*}  主函数中调用
/***********************************************************/




void user_adc_init()    //ADC转换速度为 62.836 KSPS
{
        USER_ADC_INIT adc_init_data = {0};
        user_channel_num = 2;                           //初始化为15通道,先检测外部供电电压
        adc_init_data.channel = user_channel_num;       //通道选择 占用四个字节  0~15代表16个通道 15是内部参考电压通道
        adc_init_data.resfmt = 1;                       //数据对其方式  占用一个字节 0为左对齐 1为右对齐
        adc_init_data.speed = ADC_SPEED;                //ADC时钟配置   占用4个字节 0~15 代表1~16分频
        adc_init_data.cssetup = 0;                            //通道选择时间,即准备时间   占用一个字节  0: 1ADC个时钟 1:2ADC个时钟
        adc_init_data.smpduty = 15;                     //采样时间   占用5个字节 0~31  代表1~32个ADC时钟
        adc_init_data.cshold = 2;                              //保持时间   占用2个字节 0~3 代表 1~4个ADC时钟
        adc_init_data.cvtimesel = 7;                    //自动转换次数 占用三个字节 3~7 代表1/2/4/8/16此        转换一次
        s_adc_init(&adc_init_data);                     //初始化ADC设置数据        
}




/***********************************************************/
// description: 用户ADC数据处理函数初始化
//* param {*}
//* return {*}  主函数中调用  sampling_num:采样数量   filter_count:滤波数量
/***********************************************************/


void user_adc_data_processing(ADC_DATA_PROCESSING *user_adc_data, unsigned char sampling_num, unsigned char filter_count)
{
        memset(user_adc_data, 0, sizeof(ADC_DATA_PROCESSING));
        user_adc_data ->  adc_daq_num = sampling_num;
        user_adc_data ->  adc_daq_cnt = 0;
        user_adc_data ->  adc_sampling_ok = 0;
        user_adc_data ->  adc_remove_ht_num = filter_count;
        user_adc_data ->  adc_sum = 0;
        user_adc_data ->  voltage_data = 0;
        user_adc_data ->  adc_results = 0;
}




/***********************************************************/
// description: 用户ADC初始服务函数
//* param {*}
//* return {*}  主函数中调用
/***********************************************************/
void user_adc_init_service()
{
        adc_gpio_init();
        adc_vref = CHIPID7;
        adc_vref <<= 8;
        adc_vref += CHIPID8;   //读取内部参考电压
        user_adc_data_processing(&ADC_CHANNEL_15,local_gateway_data -> user_adc_configuration.sample_count,local_gateway_data -> user_adc_configuration.filter_count);
        user_adc_data_processing(&ADC_CHANNEL_02,local_gateway_data -> user_adc_configuration.sample_count,local_gateway_data -> user_adc_configuration.filter_count);
        user_adc_data_processing(&ADC_CHANNEL_03,local_gateway_data -> user_adc_configuration.sample_count,local_gateway_data -> user_adc_configuration.filter_count);
        user_adc_data_processing(&ADC_CHANNEL_06,local_gateway_data -> user_adc_configuration.sample_count,local_gateway_data -> user_adc_configuration.filter_count);
        user_adc_data_processing(&ADC_CHANNEL_07,local_gateway_data -> user_adc_configuration.sample_count,local_gateway_data -> user_adc_configuration.filter_count);
        user_adc_data_processing(&ADC_CHANNEL_13,local_gateway_data -> user_adc_configuration.sample_count,local_gateway_data -> user_adc_configuration.filter_count);
        user_adc_data_processing(&ADC_CHANNEL_14,local_gateway_data -> user_adc_configuration.sample_count,local_gateway_data -> user_adc_configuration.filter_count);
               
        user_adc_init();                                //初始化ADC
        s_adc_dma_init((unsigned short)DMA_ADDR);       //adc_dma初始化
//        s_adc_dma_init((unsigned short)&dma_buffer[0][0]);       //adc_dma初始化        
        
        sampled_wait_time_count = local_gateway_data -> user_adc_configuration.sampling_period;  //赋值新的采样周期
}


/***********************************************************/
// description: void ADC_Isr() interrupt 5
//* param {*}
//* return {*}   ADC中断函数
/***********************************************************/


/*
void ADC_Isr() interrupt 5
{
        unsigned short temp_ushort_data = 0;
        ADC_CONTR &= ~0x20;    //清除中断标志位
        if(user_channel_num == channel_15)
        {
                temp_ushort_data = ADC_RES;
                temp_ushort_data <<= 8;
                temp_ushort_data += ADC_RESL;
                temp_ushort_data >>= 4;  // 解析实际数据
                ADC_CHANNEL_15.adc_buff[ADC_CHANNEL_15.adc_daq_cnt++] = temp_ushort_data;
    user_channel_num = CHANNEL_10;
    ADC_KC(user_channel_num);               


        }
        else if(user_channel_num == CHANNEL_10)
        {
                temp_ushort_data = ADC_RES;
                temp_ushort_data <<= 8;
                temp_ushort_data += ADC_RESL;
                temp_ushort_data >>= 4;  // 解析实际数据
                ADC_CHANNEL_10.adc_buff[ADC_CHANNEL_10.adc_daq_cnt++] = temp_ushort_data;
    user_channel_num = CHANNEL_11;
    ADC_KC(user_channel_num);                        
        }
        else if(user_channel_num == CHANNEL_11)
        {
                temp_ushort_data = ADC_RES;
                temp_ushort_data <<= 8;
                temp_ushort_data += ADC_RESL;
                temp_ushort_data >>= 4;  // 解析实际数据
                ADC_CHANNEL_11.adc_buff[ADC_CHANNEL_11.adc_daq_cnt++] = temp_ushort_data;
               
    sampled_wait_time_count = SAMPLED_WAIT_TIME;               
                if(ADC_CHANNEL_11.adc_daq_cnt >= ADC_CHANNEL_11.adc_daq_num)
                {
                        sampled_wait_time_count = 0;
                        ADC_CHANNEL_11.adc_sampling_ok = 1;  //采样完成置位
//                        temper_read_flag = 0;                //清零温度读取数据头文件
                }               
        }
}


*/
/***********************************************************/
// description: void ADC_dmaIsr() interrupt 13
//* param {*}
//* return {*}   ADC中断函数
/***********************************************************/


void ADC_DMA_Interrupt(void) interrupt 13
{
        if(DMA_ADC_STA & 0x01)   //如果中断响应为DMA_adc中断
        {
//    ADC_CONTR &= ~(0x01 << 6);        //禁用转化        
    DMA_ADC_CR &= ~(0x01 << 6);              //禁用DMA_ADC功能                        
                DMA_ADC_CR &= ~(0x01 << 7);       //禁用ADC_DMA功能
                DMA_ADC_STA = 0;
                CHANNEL01_RWT_CONTROL_GPIO = 0;
                CHANNEL01_SWT_CONTROL_GPIO = 0;
                CHANNEL02_RWT_CONTROL_GPIO = 0;
                CHANNEL02_SWT_CONTROL_GPIO = 0;  //初始化关闭检测通道               
               
                dma_adc_ok = 1;   //采样完成
        }
}




/***********************************************************/
// description: adc_int()  adc_start检测
//* param {*}
//* return {*}  
/***********************************************************/
/*
void ADC_KC(unsigned char adc_in_type)
{
                        
        switch(adc_in_type)
        {
                case CHANNEL_10:
    adc_change_channel(CHANNEL_10);
    adc_star();
                break;
                case CHANNEL_11:
    adc_change_channel(CHANNEL_11);
    adc_star();
                break;               
                case CHANNEL_15:
    adc_change_channel(CHANNEL_15);
    adc_star();        
                break;
        }
}
*/
/***********************************************************/
// description: power_voltage_count()  电源电压计算
//* param {*}
//* return {*} 内部函数调用
/***********************************************************/


unsigned short power_voltage_count(unsigned short power_adc_data)
{
        unsigned long temp_ulong_data = 0;
        temp_ulong_data = (unsigned long)adc_vref * 4096 / power_adc_data;
        return (unsigned short)temp_ulong_data;
}




/***********************************************************/
// description: adc_voltage_count()  adc电压计算
//* param {*}
//* return {*} 内部函数调用
/***********************************************************/


unsigned short adc_voltage_count(unsigned short power_voltage, unsigned short adc_data, unsigned short adc_calibration_coefficient)
{
        unsigned long temp_ulong_data = 0;
        temp_ulong_data = (unsigned long)adc_data * power_voltage / 4096;
        temp_ulong_data = temp_ulong_data * adc_calibration_coefficient / 1000;
        return (unsigned short)temp_ulong_data;        
}
















/***********************************************************/
// description: adc_data_conversion_function
//* param {*}
//* return {*} ADC数据转换函数
/***********************************************************/




void adc_data_conversion_function(ADC_DATA_PROCESSING *user_adc_data, unsigned short  p[][ADC_DATA], unsigned char data_id)
{
        unsigned short i,j,k;
        unsigned short temp_ushort_data = 0;
        if(dma_adc_ok == 1)
        {
          user_adc_data -> adc_sum = 0;
          /**************************************ADC0通道参考电压采集采集数据滤波*********************************/
                /*******************排序******************/
    for(i = 0;i < (user_adc_data -> adc_daq_num - 1); i++)
    {
        for(j = 0;j < (user_adc_data -> adc_daq_num - i - 1); j++)
        {
            if(p[data_id][j] > p[data_id][j + 1])                                          
            {
                                                          temp_ushort_data = p[data_id][j];
                                                          p[data_id][j] = p[data_id][j + 1];
                                                          p[data_id][j + 1] = temp_ushort_data;
            }
        }
    }                                
                 /***************去掉最大值最小值求平均*****************/
    for(k = user_adc_data -> adc_remove_ht_num; k < (user_adc_data -> adc_daq_num - user_adc_data -> adc_remove_ht_num); k++)
    {
        user_adc_data -> adc_sum = user_adc_data -> adc_sum + p[data_id][k];
    }               
                user_adc_data -> adc_results = (unsigned short)((user_adc_data -> adc_sum) / (user_adc_data -> adc_daq_num - (user_adc_data -> adc_remove_ht_num * 2)));
               
        }
}






/***********************************************************/
// description: adc_service()
//* param {*}
//* return {*} ADC服务函数
/***********************************************************/
unsigned short temper_buff[50] = {0};  //温度数据暂存函数
void adc_service(unsigned char *adc_sampling_ok)
{
//        unsigned short temper_buff[50] = {0};  //温度数据暂存函数
        unsigned short sys_power_voltage = 0;
        static unsigned char temper01_machion = 0;
        static unsigned char temper02_machion = 0;
        static unsigned char temper03_machion = 0;
        static unsigned char temper04_machion = 0;  //温度状态机
        if(*adc_sampling_ok == 1)
        {
               
                adc_data_conversion_function(&ADC_CHANNEL_02,dma_buffer, 0);
                adc_data_conversion_function(&ADC_CHANNEL_03,dma_buffer, 1);
                adc_data_conversion_function(&ADC_CHANNEL_06,dma_buffer, 2);
                adc_data_conversion_function(&ADC_CHANNEL_07,dma_buffer, 3);
                adc_data_conversion_function(&ADC_CHANNEL_13,dma_buffer, 4);
                adc_data_conversion_function(&ADC_CHANNEL_14,dma_buffer, 5);
                adc_data_conversion_function(&ADC_CHANNEL_15, dma_buffer, 6);
               
                sys_power_voltage = power_voltage_count(ADC_CHANNEL_15.adc_results);
               
               
                ADC_CHANNEL_02.voltage_data = adc_voltage_count(sys_power_voltage, ADC_CHANNEL_02.adc_results, local_gateway_data -> user_vol_calibration.coefficient[0]);
                ADC_CHANNEL_03.voltage_data = adc_voltage_count(sys_power_voltage, ADC_CHANNEL_03.adc_results, local_gateway_data -> user_vol_calibration.coefficient[1]);
               
                ADC_CHANNEL_06.voltage_data = adc_voltage_count(sys_power_voltage, ADC_CHANNEL_06.adc_results, local_gateway_data -> user_ntc_vol_calibration.coefficient[2]);
                modbus_reg[171] = ADC_CHANNEL_06.voltage_data;
                ADC_CHANNEL_07.voltage_data = adc_voltage_count(sys_power_voltage, ADC_CHANNEL_07.adc_results, local_gateway_data -> user_ntc_vol_calibration.coefficient[3]);
                modbus_reg[172] = ADC_CHANNEL_07.voltage_data;
                ADC_CHANNEL_13.voltage_data = adc_voltage_count(sys_power_voltage, ADC_CHANNEL_13.adc_results, local_gateway_data -> user_ntc_vol_calibration.coefficient[0]);
                modbus_reg[169] = ADC_CHANNEL_13.voltage_data;
                ADC_CHANNEL_14.voltage_data = adc_voltage_count(sys_power_voltage, ADC_CHANNEL_14.adc_results, local_gateway_data -> user_ntc_vol_calibration.coefficient[1]);
                modbus_reg[170] = ADC_CHANNEL_14.voltage_data;
               
                /************************放入NTC电阻转换函数**********************/
               
                if(user_temper01_rwt_res.temper_read_cnt < user_temper01_rwt_res.temper_read_num)
                {
                        user_temper01_rwt_res.temper_read_cnt++;
                        if(user_temper01_rwt_res.temper_read_cnt == user_temper01_rwt_res.temper_read_num)
                        {
                                temper01_machion = 1;
                                user_temper01_rwt_res.temper_read_cnt = 0;                                
                        }
                }
                user_temper01_rwt_res.adc_buff[user_temper01_rwt_res.temper_read_cnt] = temper_res_count(sys_power_voltage, ADC_CHANNEL_13.voltage_data, RREF);
    if(temper01_machion == 1)               
                {
               
                        /***********************补充温度数据滤波及查表函数*************************/
                        
                        memcpy(temper_buff, user_temper01_rwt_res.adc_buff, ((user_temper01_rwt_res.temper_read_num) * 2));  //先将数据赋值到缓存数组
                        temper_res_data_filtering(&user_temper01_rwt_res, temper_buff);                                    //对缓存数组进型排序和滤波并求出平均值
                        temper_check_table(ntc_res_data, TEMPER_TABLE_STAR_NUM, TEMPER_TABLE_STOP_NUM, (unsigned short)(user_temper01_rwt_res.temper_data_sum),
                        (unsigned short *)&(local_gateway_data -> user_temper_sampling_data.temper[0]));  //查表得出温度数据
                        
                        /***********************计算校准后数据*************************/
                        
                }
               
               
                if(user_temper01_swt_res.temper_read_cnt < user_temper01_swt_res.temper_read_num)
                {
                        user_temper01_swt_res.temper_read_cnt++;
                        if(user_temper01_swt_res.temper_read_cnt == user_temper01_swt_res.temper_read_num)
                        {
                                temper02_machion = 1;
                                user_temper01_swt_res.temper_read_cnt = 0;                                
                        }                        
                }
               
                user_temper01_swt_res.adc_buff[user_temper01_swt_res.temper_read_cnt] = temper_res_count(sys_power_voltage, ADC_CHANNEL_14.voltage_data, RREF);
    if(temper02_machion == 1)               
                {
               
                        /***********************补充温度数据滤波及查表函数*************************/
                        
                        memcpy(temper_buff, user_temper01_swt_res.adc_buff, ((user_temper01_swt_res.temper_read_num) * 2));
                        temper_res_data_filtering(&user_temper01_swt_res, temper_buff);
                        temper_check_table(ntc_res_data, TEMPER_TABLE_STAR_NUM, TEMPER_TABLE_STOP_NUM, (unsigned short)(user_temper01_swt_res.temper_data_sum),
                        (unsigned short *)&(local_gateway_data -> user_temper_sampling_data.temper[1]));  //查表得出温度数据                        
                }
               
                if(user_temper02_rwt_res.temper_read_cnt < user_temper02_rwt_res.temper_read_num)
                {
                        user_temper02_rwt_res.temper_read_cnt++;
                        if(user_temper02_rwt_res.temper_read_cnt == user_temper02_rwt_res.temper_read_num)
                        {
                                temper03_machion = 1;
                                user_temper02_rwt_res.temper_read_cnt = 0;
                        }
                }                                
                user_temper02_rwt_res.adc_buff[user_temper02_rwt_res.temper_read_cnt] = temper_res_count(sys_power_voltage, ADC_CHANNEL_06.voltage_data, RREF);
    if(temper03_machion == 1)               
                {
               
                        /***********************补充温度数据滤波及查表函数*************************/
                        
                        memcpy(temper_buff, user_temper02_rwt_res.adc_buff, ((user_temper02_rwt_res.temper_read_num) * 2));
                        temper_res_data_filtering(&user_temper02_rwt_res, temper_buff);
                        temper_check_table(ntc_res_data, TEMPER_TABLE_STAR_NUM, TEMPER_TABLE_STOP_NUM, (unsigned short)(user_temper02_rwt_res.temper_data_sum),
                        (unsigned short *)&(local_gateway_data -> user_temper_sampling_data.temper[2]));  //查表得出温度数据               
                }
               
               
                if(user_temper02_swt_res.temper_read_cnt < user_temper02_swt_res.temper_read_num)
                {
                        user_temper02_swt_res.temper_read_cnt++;
                        if(user_temper02_swt_res.temper_read_cnt == user_temper02_swt_res.temper_read_num)
                        {
                                temper04_machion = 1;
                                user_temper02_swt_res.temper_read_cnt = 0;                                
                        }
                }                        
                user_temper02_swt_res.adc_buff[user_temper02_swt_res.temper_read_cnt] = temper_res_count(sys_power_voltage, ADC_CHANNEL_07.voltage_data, RREF);
    if(temper04_machion == 1)               
                {
               
                        /***********************补充温度数据滤波及查表函数*************************/
                        
                        memcpy(temper_buff, user_temper02_swt_res.adc_buff, ((user_temper02_swt_res.temper_read_num) * 2));
                        temper_res_data_filtering(&user_temper02_swt_res, temper_buff);
                        temper_check_table(ntc_res_data, TEMPER_TABLE_STAR_NUM, TEMPER_TABLE_STOP_NUM, (unsigned short)(user_temper02_swt_res.temper_data_sum),
                        (unsigned short *)&(local_gateway_data -> user_temper_sampling_data.temper[3]));  //查表得出温度数据                                
                }
               
                /***********************放入DAC输出电压反馈采集转换函数************/
                local_gateway_data -> user_dac_output_vol.value[0] = dac_output_vol_conversion(ADC_CHANNEL_02.voltage_data, TOTAL_RES, PULL_DOWN_RES);
                local_gateway_data -> user_dac_output_vol.value[1] = dac_output_vol_conversion(ADC_CHANNEL_03.voltage_data, TOTAL_RES, PULL_DOWN_RES);
               
               
                /***********************放入DAC输出电压反馈PID计算函数************/
                                
                sampled_wait_time_count = local_gateway_data -> user_adc_configuration.sampling_period;  //赋值新的采样周期
                *adc_sampling_ok = 0;        
        }
        
        
}














/***********************************************************/
// description: void adc_1ms()
//* param {*}
//* return {*} adc 1ms中断函数  open_flag: 开启计时标志位 或读取传感器数据标志位
/***********************************************************/
unsigned short sampled_wait_time_count = 0;   //采样间隔时间计数


void adc_1ms()
{
  if(sampled_wait_time_count > 0)
        {
                sampled_wait_time_count--;
                if(sampled_wait_time_count == 0)
                {
                        DMA_ADC_CR |= 0x01 << 7;         //先使能ADC_DMA功能
                        CHANNEL01_RWT_CONTROL_GPIO = 1;
                        CHANNEL01_SWT_CONTROL_GPIO = 1;
                        CHANNEL02_RWT_CONTROL_GPIO = 1;
                        CHANNEL02_SWT_CONTROL_GPIO = 1;  //拉低检测下管开启检测                        
                        _nop_();
                        _nop_();
                        _nop_();
                        _nop_();
                        _nop_();                                           //延时使拉低过程稳定下来
                        adc_dma_star();                  //触发DMA
                }
        }
}





回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:7
  • 最近打卡:2026-02-23 11:11:05
已绑定手机

5

主题

4

回帖

53

积分

注册会员

积分
53
发表于 2026-2-19 23:39:47 | 显示全部楼层
目前用的MCU型号为:STC8H8K64U  LQFP-64   编译完成: Program Size: data=9.0 xdata=3555 const=7 code=18750
截图202602192339431999.jpg
回复

使用道具 举报 送花

  • 打卡等级:初来乍到
  • 打卡总天数:7
  • 最近打卡:2026-02-23 11:11:05
已绑定手机

5

主题

4

回帖

53

积分

注册会员

积分
53
发表于 2026-2-23 11:11:05 | 显示全部楼层
经尝试,我之前MCU运行频率44.2368mhz,会出现RAM随机乱写的问题,但是降频到33.1776mhz后问题消失,连续跑了一段时间没有出现复现,意思是RAM的总线频率达不到这么高吗?但是我之前在其他项目上也经常用这个频率,没出过问题
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:347
  • 最近打卡:2026-03-07 12:55:14

842

主题

1万

回帖

2万

积分

管理员

积分
22606
发表于 2026-2-23 14:38:32 | 显示全部楼层
保守点,跑 <= 40MHz
回复

使用道具 举报 送花

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

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-3-7 15:32 , Processed in 0.109743 second(s), 58 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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