一、应用场景

  有时候会遇到两个设备进行异步通信的情况,比如串口,没有同步时钟,靠波特率来约定采样时间,假设波特率为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 }