stc+dac0800方案能做到步进0.1hz的40-400hz范围256点数正弦波吗
如题,stc这边是并口,8个IO口同时输出正弦码表给DAC0800,正弦波的频率控制在40-400hz,调整步进在0.1hz,每周期256个点。请问用C语言的情况下,应该怎么实现呢?
或者说,能实现吗? 步进0.1Hz实现不了 本帖最后由 michaelli594 于 2022-11-7 19:50 编辑
MYQQ2021 发表于 2022-11-7 19:42
步进0.1Hz实现不了
(引用自2楼)
我看市面上有产品就是这方案也能实现,而且晶振只有30M。
我就觉得神奇也百思不得其解,所以我就问问坛友们,看看有没有知道咋回事的 可以实现
用DDS的方式
参考AD9833,28bit相位累加器,内部DAC 1Msps更新率下输出频率分辨率为0.004Hz
自己搭电路的话,DAC挂总线上,用MOVX指令访问,实现200Ksps的更新率,软件实现DDS,24bit相位累加器,频率分辨率为 200K/2^24 = 0.012Hz 本帖最后由 michaelli594 于 2022-11-7 20:59 编辑
20061002838 发表于 2022-11-7 19:55
可以实现
用DDS的方式
参考AD9833,28bit相位累加器,内部DAC 1Msps更新率下输出频率分辨率为0.004Hz
(引用自4楼)
大神你好,
首先你说的DAC直接挂总线上,我理解的话就是直接把51的8个IO(假设P0)直接连到DAC0800的B1-B8,这没错吧?!
然后就是你说的用“用MOVX指令访问”并且实现24bit的相位累加器,这个过程中,都是用汇编指令来实现吗?
20061002838 发表于 2022-11-7 19:55
可以实现
用DDS的方式
参考AD9833,28bit相位累加器,内部DAC 1Msps更新率下输出频率分辨率为0.004Hz
(引用自4楼)
还有就是200ksps更新率是怎么得出来的,能说说吗 michaelli594 发表于 2022-11-7 20:57
大神你好,
首先你说的DAC直接挂总线上,我理解的话就是直接把51的8个IO(假设P0)直接连到DAC0800的B1-B ...
(引用自5楼)
看了下DAC的规格书,不需要挂在总线上面,直接往完整的8bit IO口写数据就好了,不需要MOVX指令的
200K是我估计的,DDS的流程挺简单的,定时器中断,24bit的相位累计,截取高八位,查正弦波,IO输出,这些一起我估计几十个周期足够了 本帖最后由 michaelli594 于 2022-11-7 22:28 编辑
20061002838 发表于 2022-11-7 21:52
看了下DAC的规格书,不需要挂在总线上面,直接往完整的8bit IO口写数据就好了,不需要MOVX指令的
200K是 ...
(引用自7楼)
如果按照你说的定时器中断的方式查表输出的话,精度远远不够喔。
我试过用25M的晶振外挂到stc15单片机上,也是定时器用查表输出,
100hz内还是可以微调0.1hz,但是往上的话就不能微调了。
25Mhz下的1T定时器每次计数最快也才40ns,而400hz和399.9hz之间的周期只相差几个ns。
不过也有可能是我的做法不对,请多多指教
我的流程大致是这样的
u8 正弦码表;
u8 a;
void 定时器中断{
P0=正弦码表;
} 本帖最后由 国学芯用 于 2022-11-8 11:23 编辑
差不多十年前用STC12系列做过类似的东西,当时做的是频率与强度都可调;调频时不太理想,重新计算正弦表比较花时间,导致输出卡顿,后来改用STC32实现了,使用两个正弦表,过零时切表。 hzyyl2008 发表于 2022-11-8 11:06
差不多十年前用STC12系列做过类似的东西,当时做的是频率与强度都可调;调频时不太理想,重新计算正弦表比 ...
(引用自9楼)
正弦表用固定值不好吗?我这也是频率和幅值可调的,只不过目前是频率这里卡住了 michaelli594 发表于 2022-11-8 11:12
正弦表用固定值不好吗?我这也是频率和幅值可调的,只不过目前是频率这里卡住了 ...
(引用自10楼)
调频后需要重新计算正弦表 michaelli594 发表于 2022-11-7 22:16
如果按照你说的定时器中断的方式查表输出的话,精度远远不够喔。
我试过用25M的晶振外挂到stc15单片机上 ...
(引用自8楼)
你把最重要的相位累加步骤给漏掉了 可以的,不考虑别的程序需要时间,仅仅输出频率,模拟DDS。
使用STC8系列MCU,跑32.768MHz。
0.1Hz步进,最高400Hz,则累加器=4000。256点正弦波则采样fs=256*4000=1024KHz,则每个采样处理时间为32个时钟,完全没有问题。
我用STC8系列做DDS用一组IO接R-2R做DAC输出正弦波,跑32.768MHz,用汇编写程序,24位累加器,采样2048KHz,最高输出
300Khz正弦波,步进0.122Hz。
我用STC32G系列做DDS用一组IO接R-2R做DAC输出正弦波,跑32.768MHz,用C写程序,32位累加器,采样3276800Hz,最高输出
500Khz正弦波,步进0.001Hz。
本帖最后由 michaelli594 于 2022-11-8 16:03 编辑
20061002838 发表于 2022-11-8 11:46
你把最重要的相位累加步骤给漏掉了
(引用自12楼)
你好,关于相位累加的概念我查阅了部分资料,发现大部分都是针对fpga和pld的实现。
请问有c语言描述的吗?或者你再展开说说?
https://zhidao.baidu.com/question/392182330.html
按照我在百度上搜到的这个:
就是在系统时钟+1后,相位变量每次自增1/x(x=时钟的频率/输出波形频率),
再根据这个相位变量的值计算一次正弦码表的值再输出?
不过我感觉好像怪怪的 本帖最后由 michaelli594 于 2022-11-8 16:06 编辑
小李非刀 发表于 2022-11-8 12:17
可以的,不考虑别的程序需要时间,仅仅输出频率,模拟DDS。
使用STC8系列MCU,跑32.768MHz。
0.1Hz步进,最 ...
(引用自13楼)
厉害厉害!
那如果用stc15的1T单片机25M晶振来写的话,
只能用汇编才能实现我想要的400hz内0.1hz步进的要求吗?
c语言能实现吗 搞48位的相位累加器就想多细有多细了,你找一个ad9854挂上2M的时钟,输出的理论分辨率细到你没法测量,但写代码为主的基本上不会有相位累加器的概念,用简单定时器的思维就需要时钟足够高才能做出来分辨率或者最多搞个小数分频的pll。所以并不是用啥单片机的问题 本帖最后由 michaelli594 于 2022-11-8 17:28 编辑
ibmx311 发表于 2022-11-8 17:11
搞48位的相位累加器就想多细有多细了,你找一个ad9854挂上2M的时钟,输出的理论分辨率细到你没法测量,但写 ...
(引用自16楼)
你好,首先像dds芯片大多都太贵了。
然后就是代码方面相位累加器这个概念对于我来说是个新的概念,我想学习一下。
最后小数分频的pll这个好像也挺特别的。
(好像没碰到有单片机还能这样操作?!)
michaelli594 发表于 2022-11-8 14:27
厉害厉害!
(引用自15楼)
你的最高频率才400Hz,用C写也很容易实现。 不是单片机的事情这才是关键 小李非刀 发表于 2022-11-8 17:27
你的最高频率才400Hz,用C写也很容易实现。
(引用自18楼)
好的,我明天尝试下,感觉有点思路了{:lol:} 本帖最后由 20061002838 于 2022-11-8 18:41 编辑
michaelli594 发表于 2022-11-8 14:23
你好,关于相位累加的概念我查阅了部分资料,发现大部分都是针对fpga和pld的实现。
请问有c语言描述的吗 ...
(引用自14楼)
试试看吧
原理都是一样的,用FPGA PLD是为了实现更高的DAC更新率,对你而言不需要这么快,所以MCU足够了 20061002838 发表于 2022-11-8 18:39
试试看吧
原理都是一样的,用FPGA PLD是为了实现更高的DAC更新率,对你而言不需要这么快,所以MCU足够了 ...
(引用自21楼)
好的,感谢回复
本帖最后由 michaelli594 于 2022-11-9 11:10 编辑
很奇怪,应该是哪里弄错了?!(参考https://blog.csdn.net/weixin_36176546/article/details/117161005)
设置的时钟频率是500k,输出频率为400,示波器测的结果却是37.6hz左右???
是我哪里写的不对吗?有点懵
(stc15的1t单片机+25M外部晶振)(中断周期没问题)
代码如下:
typedef data struct DDS_info{
float fre_out;//输出频率
float fre_clk;//采样频率
float M;//累加器位数
float FTW;//频率控制字
u32 phase;//累加器
u32 ftw_1hz;//1hz对应的频率控制字
u32 ftwacc;//当前频率控制字
u8 i;
}DDS_info_;
#define fre_fosc (5*1e5)
void exint1() interrupt 2 //INT1中断入口
{
DDS_.phase+=DDS_.ftwacc;
DDS_.i=DDS_.phase>>24;
P0=sin_;
}
void Fre_init(float fre_out){
DDS_.fre_clk=fre_fosc;
DDS_.M=32;
DDS_.FTW=pow(2,DDS_.M)/DDS_.fre_clk;
DDS_.ftw_1hz=(u32)(DDS_.FTW)+1;
DDS_.ftwacc=(u32)(DDS_.FTW*fre_out)+1;
DDS_.phase=0;
P0=0; //正弦波并口
P45=1; //片选
P33 = 1; //中断脚
IT1 = 1; //设置INT1的中断类型 (1:仅下降沿 0:上升沿和下降沿)
EX1 = 1; //使能INT1中断
Timer1Init(65536-25); //500khz触发中断
} 本帖最后由 michaelli594 于 2022-11-10 09:46 编辑
小李非刀 发表于 2022-11-8 12:17
可以的,不考虑别的程序需要时间,仅仅输出频率,模拟DDS。
使用STC8系列MCU,跑32.768MHz。
0.1Hz步进,最 ...
(引用自13楼)
版主你好,我现在这样是20个时钟处理一次。
浮点输入值是400,但是为啥出来的正弦波是20.00hz??(25M的晶振 stc15单片机)
typedef data struct DDS_info{
u32 value;//累加器
u32 add;//当前频率控制字
u8 i;
}DDS_info_;
DDS_info_ DDS_;
void exint1() interrupt 2 //1.25MhzINT1中断入口
{
DDS_.value+=DDS_.add;
DDS_.i=DDS_.value>>16;
P0=sin_;
}
void Fre_init(float fre_out){
DDS_.add=(u32)(pow(2,24)/(1.25*1e6)*fre_out)+1;
DDS_.value=0;
Timer1Init(65536-10); //定时器时钟输出2次触发一次外部
} 路子都不对,鉴定完毕 ibmx311 发表于 2022-11-10 11:45
路子都不对,鉴定完毕
(引用自25楼)
这么尴尬的吗{:dizzy:} 能说说不 michaelli594 发表于 2022-11-10 09:44
版主你好,我现在这样是20个时钟处理一次。
浮点输入值是400,但是为啥出来的正弦波是20.00hz??(25M的 ...
(引用自24楼)
为了尽量快,直接单个变量操作,不要用结构体。 michaelli594 发表于 2022-11-8 11:12
正弦表用固定值不好吗?我这也是频率和幅值可调的,只不过目前是频率这里卡住了 ...
(引用自10楼)
步进可以细分,正弦点在前后两个点基础上插值。
页:
[1]