一、应用场景
有时候会遇到两个设备进行异步通信的情况,比如串口,没有同步时钟,靠波特率来约定采样时间,假设波特率为921600,接收端时钟频率为50MHz,那么一个bit需要50000000/921600≈54.25个时钟,但是实际数时钟个数不可能有小数,因此实际接收端波特率和发送端波特率会有一个误差,如果接收端始终按照固定的时钟间隔采样的话,并且在连续采集模式下,随着时间的推移误差会越来越大,最终带来的结果是采样出错。有一个解决办法是调整输入时钟,FPGA的PLL是乘以一个1~256之间的整数,然后除以一个1~256之间的整数得到一个新的频率,但是得到的频率有上限。
其实举这个例子不合适,因为串口会在每次接收到起始位的时候校准,不存在误差累计的问题。
二、程序代码
1 #include <stdio.h> 2 #include <math.h> 3 #include <stdlib.h> 4 5 void main(void) 6 { 7 int m, d, k, min_m, min_d; 8 const double in_freq = 50000000.0; /* 输入频率 */ 9 const double boad_rate = 921600.0; /* 期望波特率 */ 10 const double bit_cnt = 210; /* 连续发送的位数 */ 11 const double max_out_freq = 315000000.0; /* 最大输出频率 */ 12 13 double out_freq = 0; /* 输出频率 */ 14 double min_err = 100; 15 double err = 0; 16 double clk_cnt = 0; 17 double frame_time_us_send = 1000000 * bit_cnt / boad_rate; /* 发送端发送一帧需要的时间 */ 18 double frame_time_us_recv; /* 接收端接收一帧需要的时间 */ 19 20 for (k = 0; k < 2; k++) { 21 for (m = 1; m <= 256; m++) { 22 for (d = 1; d <= 256; d++) { 23 out_freq = in_freq * (double)m / (double)d; 24 if (out_freq > max_out_freq) { /* 不能超过最高频率 */ 25 continue; 26 } 27 28 clk_cnt = floor(out_freq / boad_rate); 29 if (clk_cnt < 5) { /* 小于5个时钟的处理不了 */ 30 continue; 31 } 32 33 frame_time_us_recv = clk_cnt * bit_cnt * 1000000 / out_freq; 34 35 err = fabs(frame_time_us_recv - frame_time_us_send); 36 37 if (k == 0) { 38 if (err < min_err) { 39 min_err = err; 40 min_m = m; 41 min_d = d; 42 } 43 44 /* 看一眼不用PLL误差有多大 */ 45 #if 0 46 if ((m == 1 && d == 1) || (err < 0.01)) { /* 打印出所有误差小于0.1的结果 */ 47 printf("M = %d\n", m); 48 printf("D = %d\n", d); 49 printf("frame_time_us_send = %f\n", frame_time_us_send); 50 printf("frame_time_us_recv = %f\n", frame_time_us_recv); 51 printf("clk_cnt = %f\n", clk_cnt); 52 printf("err = %fus\n\n", err); 53 } 54 #endif 55 } else { 56 if (err == min_err) { /* 输出所有最优解 */ 57 printf("M = %d\n", m); 58 printf("D = %d\n", d); 59 printf("输出频率 = %fMHz\n", out_freq / 1000000); 60 printf("最小误差 = %fus\n\n", err); 61 } 62 } 63 } 64 } 65 } 66 67 68 69 70 }
浙公网安备 33010602011771号