新手入门
- 积分
- 14
- 金钱
- 14
- 注册时间
- 2021-5-27
- 在线时间
- 6 小时
|
本帖最后由 你给的安然c 于 2021-6-1 09:56 编辑
最近在做一个数据采集的项目,用的是STM32F407和8通道同步采样adc ad7606,要求实时记录采集的ADC值,网上找了找用fsmc 实现ad7606采集的程序,目前能够实现8个通道的单次采样和以某个采样率(比如10k,50K,100K等等)自动采样。
上面的图是7606手册上的读取数据的时序图,产生PWM波的引脚接了7606的convstAB,PC5接了7606的busy,再将PC5配置成外部中断,在外部中断里面通过FSMC将7606转换的数据读出来(时间大概1us再加上存数组可能2us),就可以实现以某个采样率自动采样。但问题出在数据存储上,假设我采样率设置为50K,那么8通道的数据加起来会达到800KB/s,这要求带文件系统的情况下写SD卡的速度要大于800KB/s,同时意味着每隔20us将进一次外部中断读取数据,因此,我的想法是设置两个缓冲数组,两个数组在中断里面交替接收数据(buf1满了,将ADC值存到buf2,buf2满了将ADC值存到buf1,类似于双缓冲),在主程序中将存满的缓冲数组通过文件系统写到SD卡中,其中,缓冲数组大小为4096字节,这样相当于一个缓冲数组就可以接收256次ad7606的数据(ad7606的adc是16位),这也相当于为主程序写SD卡争取了256*(20-1)=4864us。我在外部中断里面增加了缓冲数组溢出判断,假设buf1存满了,buf1满标志置为1,之后进外部中断adc值将存到buf2,这个时候主程序能在4864us内写完sd卡,会将把buf1满标志置0,代表buf1已准备好,buf2满了后又可以换成buf1继续接收。但下载后运行,他会一直提示溢出,我把采样率降低获取更多时间,或者提高缓冲数组大小,同样存在这个问题。我暂时没想明白问题出在哪,可能是逻辑错误,希望大佬们帮我看看。整体的代码是在原子的录音机实验上改的,部分代码在下面:
typedef struct
{
uint8_t ucOS; /* 过采样 */
uint8_t ucRange; /* 量程*/
int16_t sNowAdc[8]; /* 当前ADC值 */
}AD7606_VAR_T;
/********************FIFO结构体********************/
typedef struct
{
/* FIFO参数*/
uint16_t usRead; /* 读指针*/
uint16_t usWrite; /* 写指针*/
uint16_t usCount_Bytes; /* 计数 */
uint8_t UseFiof1_flag; /* FIFO使用标志 */
uint8_t UseFiof2_flag;
uint8_t Fifo1Full_flag; /* FIFO满标志 */
uint8_t Fifo2Full_flag;
uint8_t FullDiasable1; /*FIFO*/
}AD7606_FIFO_T;
u8 *sBuf_Adc1;
u8 *sBuf_Adc2;
u8 *sBuf_HexToStr1;
u8 *sBuf_HexToStr2;
/**********外部中断里面的ADC读取代码***********/
void AD7606_ISR_new(void)
{
uint8_t i;
if(rec_sta==0X80)//录音模式
{
AD7606_ReadNowAdc(); //读取ADC值
if(g_tAdcFifo.UseFiof1_flag == 1 && g_tAdcFifo.Fifo1Full_flag == 1)
{
printf("FIFO1溢出\r\n");
}
if(g_tAdcFifo.UseFiof2_flag == 1 && g_tAdcFifo.Fifo2Full_flag == 1)
{
printf("FIFO2溢出\r\n");
}
/******使用fifo1*******/
if(g_tAdcFifo.UseFiof1_flag == 1 /*&& g_tAdcFifo.Fifo1Full_flag == 0*/)
{
for (i = 0; i < 8; i++)
{
sBuf_Adc1[g_tAdcFifo.usWrite] = g_tAD7606.sNowAdc & 0xff; //存低8位
g_tAdcFifo.usWrite++;
sBuf_Adc1[g_tAdcFifo.usWrite] = (g_tAD7606.sNowAdc>>8) & 0xff; //存高8位 这里后面用了联合体定义,省去了将16位转为2个8位的时间,但还是会存在上面溢出的问题
g_tAdcFifo.usWrite++;
}
if (g_tAdcFifo.usWrite >= ADC_FIFO_SIZE) //4096字节 buf1存满
{
g_tAdcFifo.usWrite = 0;
g_tAdcFifo.Fifo1Full_flag = 1; /* FIFO1满 */
g_tAdcFifo.UseFiof1_flag = 0; /* 关掉 FIFO1 */
g_tAdcFifo.UseFiof2_flag = 1; /* 使用 FIFO2 */
g_tAdcFifo.FullDiasable1 = 1; /*从上往下执行,避免buf1满后,立马写buf2*/
}
g_tAdcFifo.usCount_Bytes+=2; /* 计数 */
}
/******使用fifo2*******/
if(g_tAdcFifo.UseFiof2_flag == 1 && g_tAdcFifo.FullDiasable1 == 0)
{
for (i = 0; i < 8; i++)
{
sBuf_Adc2[g_tAdcFifo.usWrite] = g_tAD7606.sNowAdc & 0xff; //低8位
g_tAdcFifo.usWrite++;
sBuf_Adc2[g_tAdcFifo.usWrite] = (g_tAD7606.sNowAdc>>8) & 0xff; //高8位
g_tAdcFifo.usWrite++;
}
if (g_tAdcFifo.usWrite >= ADC_FIFO_SIZE)
{
g_tAdcFifo.usWrite = 0;
g_tAdcFifo.Fifo2Full_flag = 1; /* FIFO2满 */
g_tAdcFifo.UseFiof2_flag = 0; /* 关掉 FIFO2 */
g_tAdcFifo.UseFiof1_flag = 1; /* 使用 FIFO1 */
}
g_tAdcFifo.usCount_Bytes+=2; /* 计数 */
}
if(g_tAdcFifo.Fifo1Full_flag == 1)g_tAdcFifo.FullDiasable1 = 0; //buf1满后 下一次中断 buf2可以使用
}
}
/**********主程序中通过文件系统写SD卡***********/
void AD7606_ReadFifo(void)
{
u8 res;
if(g_tAdcFifo.Fifo1Full_flag == 1)
{
HexToStr(sBuf_HexToStr1,sBuf_Adc1,ADC_FIFO_SIZE); //这一步是转字符,之前以为写txt比写wav快 就试了一下,可以忽略
/************将FIFO1写到SD卡*************/
res = f_write(f_rec_txt, sBuf_HexToStr1, ADC_FIFO_SIZE*2, &bw);
if(res)printf("write error:%d\r\n",res);
/*************************************/
INTX_DISABLE();//关掉总中断
g_tAdcFifo.Fifo1Full_flag = 0;
INTX_ENABLE();//开启总中断
wavsize+=ADC_FIFO_SIZE;
}
if(g_tAdcFifo.Fifo2Full_flag == 1)
{
HexToStr(sBuf_HexToStr2,sBuf_Adc2,ADC_FIFO_SIZE);
/************将FIFO2写到SD卡*************/
res = f_write(f_rec_txt, sBuf_HexToStr2, ADC_FIFO_SIZE*2, &bw);
if(res)printf("write error:%d\r\n",res);
/*************************************/
INTX_DISABLE();//关掉总中断
g_tAdcFifo.Fifo2Full_flag = 0;
INTX_ENABLE();//开启总中断
wavsize+=ADC_FIFO_SIZE;
}
}
/**********下面是主程序***********/
void wav_recorder_new1(void)
{
u8 res;
u8 key;
u8 rval=0;
DIR recdir; //目录
u8 *pname = 0;
u8 timecnt=0; //计时
u32 recsec=0; //录音时间
while(f_opendir(&recdir,"0:/RECORDER"))//打开录音文件夹
{
printf("RECORDER文件夹错误!\r\n");
delay_ms(200);
f_mkdir("0:/RECORDER"); //创建文件夹
}
/**************************分配内存***************************/
f_rec_txt = (FIL *)mymalloc(SRAMIN,sizeof(FIL));
pname = mymalloc(SRAMIN,30);
sBuf_Adc1 = mymalloc(SRAMIN, ADC_FIFO_SIZE);
sBuf_Adc2 = mymalloc(SRAMIN, ADC_FIFO_SIZE);
sBuf_HexToStr1 = mymalloc(SRAMIN, ADC_FIFO_SIZE*2);
sBuf_HexToStr2 = mymalloc(SRAMIN, ADC_FIFO_SIZE*2);
if(!sBuf_Adc1||!sBuf_Adc2||!sBuf_HexToStr1||!sBuf_HexToStr2|| \
!f_rec_txt|| \
/*!wavhead|| */
!pname)rval=1;
if(rval==0)
{
recoder_enter_rec_mode(); //这里我改了 仅仅显示按键信息
pname[0]=0; //pname没有任何文件名
while(rval==0)
{
if(rec_sta==0X80)//录音模式
{
AD7606_ReadFifo(); //写sd卡
}
key=KEY_Scan(0);
switch(key)
{
case KEY1_PRES: //STOP&SAVE
if(rec_sta&0X80)//有录音
{
rec_sta=0; //关掉录音
AD7606_StopRecord(); /*停止自动采集,关掉了外部中断 */
f_close(f_rec_txt);
wavsize=0;
printf("录音结束\r\n");
}
rec_sta=0;
recsec=0;
LED1=1; //关闭DS1
break;
case KEY0_PRES: //REC/PAUSE
if(rec_sta&0X01)//原来是暂停,继续录音
{
rec_sta&=0XFE;//取消暂停
}else if(rec_sta&0X80)//已经是录音,暂停
{
rec_sta|=0X01; //暂停
}else //开始录音
{
recsec=0;
recoder_new_pathname_new1(pname);
printf("录制:\r\n");
printf("%s\r\n",pname);//显示当前录音文件名字
res = f_open(f_rec_txt,(const TCHAR*)pname, FA_CREATE_ALWAYS | FA_WRITE);
if(res)
{
printf("write error:%d\r\n",res);
rec_sta=0; //创建文件失败,不能录音
rval=0XFE; //提示SD卡是否存在
}
else
{
recoder_msg_show(0,0);
rec_sta|=0X80; //开始录音
AD7606_StartRecord(50000); /*50khz采样*/
}
}
if(rec_sta&0X01)LED1=0; //提示暂停
else LED1=1;
break;
}
delay_ms(5);
timecnt++;
if((timecnt%20)==0)LED0=!LED0;//DS0闪烁
if(recsec!=(wavsize/wavhead->fmt.ByteRate))
{
LED0=!LED0;//DS0闪烁
recsec=wavsize/wavhead->fmt.ByteRate; 更新时间
recoder_msg_show(recsec,wavhead->fmt.SampleRate*wavhead->fmt.NumOfChannels*wavhead->fmt.BitsPerSample);//更新显示
}
}
}
/********清内存*******/
myfree(SRAMIN,f_rec_txt);
myfree(SRAMIN,pname);
myfree(SRAMIN,sBuf_Adc1);
myfree(SRAMIN,sBuf_Adc2);
myfree(SRAMIN,sBuf_HexToStr1);
myfree(SRAMIN,sBuf_HexToStr2);
}
|
|