本次实验是在“基于Verilog HDL的ADC0809CCN数据采样”实验上进一步改进,利用ADC0809采集到的8位数据,进行BCD编码,以供查表方式相加进行显示,本次实验用三位数码管。
ADC0809的8位数数据BCD编码方式,低四位与高四位分开进行编码,其对应值我也是从网上得来的,具体对应值请看代码,编完码得到12位宽的数据后,对两个编码进行相加,如代码中的cout[11:0] = L[11:0] + H[11:0],这里注意,高四位[11:8]、中四位[7:4]、低四位[3:0]。
假如ADC0809得到的数据是8'hb4,从代码中可以看到,低四位4'h4: L <= 12'h008;高四位4'hb: H <= 12'h352;,H+L = 12’h35A,低位为A,大于9,向中位产生进位C0= 1,其低位得加6得到0,故cout[11:0]=12'h360,电压也就是3.60V,然后把360送给数码管进行显示。同理如果中位相加大于9也得向高位进位C1,此时的中位要变为加6后的值。
代码实现:
display_control.v
1 module display_control( 2 //input 3 sys_clk,//27MHZ 4 rst_n, 5 seg_data,//ADC0809传送进来的数据 6 7 //output 8 slec_wei, 9 slec_duan 10 ); 11 input rst_n; 12 input [7:0] seg_data; 13 input sys_clk; 14 15 output [3:0] slec_wei; 16 output [6:0] slec_duan; 17 18 /*****************************************/ 19 parameter SEG_NUM0 = 7'h3f, 20 SEG_NUM1 = 7'h06, 21 SEG_NUM2 = 7'h5b, 22 SEG_NUM3 = 7'h4f, 23 SEG_NUM4 = 7'h66, 24 SEG_NUM5 = 7'h6d, 25 SEG_NUM6 = 7'h7d, 26 SEG_NUM7 = 7'h07, 27 SEG_NUM8 = 7'h7f, 28 SEG_NUM9 = 7'h6f, 29 SEG_NUMa = 7'h77, 30 SEG_NUMb = 7'h7c, 31 SEG_NUMc = 7'h39, 32 SEG_NUMd = 7'h5e, 33 SEG_NUMe = 7'h79, 34 SEG_NUMf = 7'h71; 35 parameter T5MS = 18'd134_999; 36 /************************************/ 37 //低四位BCD编码 38 reg [11:0] L; 39 always @ (posedge sys_clk) 40 case(seg_data[3:0]) //L = n * 12'h002(n=1、2、3、、f) 41 4'h1: L <= 12'h002; 42 4'h2: L <= 12'h004; 43 4'h3: L <= 12'h006; 44 4'h4: L <= 12'h008; 45 4'h5: L <= 12'h010; 46 4'h6: L <= 12'h012; 47 4'h7: L <= 12'h014; 48 4'h8: L <= 12'h016; 49 4'h9: L <= 12'h018; 50 4'ha: L <= 12'h020; 51 4'hb: L <= 12'h022; 52 4'hc: L <= 12'h024; 53 4'hd: L <= 12'h026; 54 4'he: L <= 12'h028; 55 4'hf: L <= 12'h030; 56 default : L <= 12'h000; 57 endcase 58 /************************************/ 59 //高四位BCD编码 60 reg [11:0] H; 61 always @ (posedge sys_clk) 62 case(seg_data[7:4]) //H = n * 12'h032(n=1、2、3、、f) 63 4'h1: H <= 12'h032; //12'b0000_0011_0010; 64 4'h2: H <= 12'h064; //12'b0000_0110_0100; 65 4'h3: H <= 12'h096; //12'b0000_1001_0110; 66 4'h4: H <= 12'h128; //12'b0001_0010_1000; 67 4'h5: H <= 12'h160; //12'b0001_0110_0000; 68 4'h6: H <= 12'h192; //12'b0001_1001_0010; 69 4'h7: H <= 12'h224; //12'b0010_0010_0100; 70 4'h8: H <= 12'h256; //12'b0010_0101_0110; 71 4'h9: H <= 12'h288; //12'b0010_1000_1000; 72 4'ha: H <= 12'h320; //12'b0011_0010_0000; 73 4'hb: H <= 12'h352; //12'b0011_0101_0010; 74 4'hc: H <= 12'h384; //12'b0011_1000_0100; 75 4'hd: H <= 12'h416; //12'b0100_0001_0110; 76 4'he: H <= 12'h448; //12'b0100_0100_1000; 77 4'hf: H <= 12'h480; //12'b0100_1000_0000; 78 default : H <= 12'h000; //12'b0000_0000_0000; 79 endcase 80 /************************************/ 81 //判断低四位是否大于9并进位 82 reg c0; 83 always @ (posedge sys_clk) 84 begin 85 if(H[3:0] + L[3:0] > 4'd9) 86 c0 <= 1; 87 else 88 c0 <= 0; 89 end 90 /************************************/ 91 //判断中间四位是否大于9并进位 92 reg c1; 93 always @(posedge sys_clk) 94 begin 95 if(H[7:4] + L[7:4] > 4'd9) 96 c1 <= 1; 97 else 98 c1 <= 0; 99 end 100 /***********************************************/ 101 //对进位进行计算,中四位减去2,低四位加上1,是为了校准显示电压与实测电压更为接近,根据情况而定 102 reg [11:0] cout; 103 always @(c1 or c0) 104 begin 105 case({c1,c0}) 106 2'b00: begin 107 cout[11:8] <= H[11:8] + L[11:8]; 108 cout[7:4] <= H[7:4] + L[7:4] - 4'd2;//减去4'd2是为了校准显示电压,与实际测试更为接近 109 cout[3:0] <= H[3:0] + L[3:0] + 1'd1;//减去1'd1是为了校准显示电压,与实际测试更为接近 110 end 111 112 2'b01: begin 113 if((H[7:4] + L[7:4] + 4'b0001) > 9) begin 114 cout[11:8] <= H[11:8] + L[11:8] + 4'b0001; 115 cout[7:4] <= H[7:4] + L[7:4] + 4'b0111 - 4'd2;//加上6并加上来自低位上的进位 116 cout[3:0] <= H[3:0] + L[3:0]+ 4'b0110 + 1'd1;//加上6 117 end 118 else begin 119 cout[11:8] <= H[11:8] + L[11:8]; 120 cout[7:4] <= H[7:4] + L[7:4] + 4'b0001 - 4'd2; 121 cout[3:0] <= H[3:0] + L[3:0] + 4'b0110 + 1'd1; 122 end 123 end 124 125 2'b10:begin 126 cout[11:8] <= H[11:8] + L[11:8] + 4'b0001; 127 cout[7:4] <= H[7:4] + L[7:4] + 4'b0110 - 4'd2; 128 cout[3:0] <= H[3:0] + L[3:0] + 1'd1; 129 end 130 131 2'b11:begin 132 cout[11:8] <= H[11:8] + L[11:8] + 4'b0001; 133 cout[7:4] <= H[7:4] + L[7:4] + 4'b0110 - 4'd2; 134 cout[3:0] <= H[3:0] + L[3:0] + 4'b0110 + 1'd1; 135 end 136 endcase 137 end 138 139 /**********************************************/ 140 //5ms计数器 141 reg [17:0] cnt; 142 always @(posedge sys_clk or negedge rst_n) 143 if(!rst_n) 144 cnt <= 18'd0; 145 else if(cnt == T5MS) 146 cnt <= 18'd0; 147 else 148 cnt <= cnt + 1'b1; 149 /**********************************************/ 150 //通过移位方式进行流水工作,定时开关 151 reg [2:0] slec_wei_temp; 152 always @(posedge sys_clk or negedge rst_n) 153 if(!rst_n) begin 154 slec_wei_temp <= 3'd011; 155 end 156 else if(cnt == T5MS) begin 157 if(slec_wei_temp == 3'b110) 158 slec_wei_temp <= 3'b011; 159 else 160 slec_wei_temp <= {1'b1,slec_wei_temp[2:1]}; 161 end 162 163 assign slec_wei = {1'b1,slec_wei_temp}; 164 /*****************************************/ 165 reg [6:0] data0; 166 always @ (posedge sys_clk) 167 case(cout[11:8]) //进行编码 高 168 4'h0: data0 <= SEG_NUM0; 169 4'h1: data0 <= SEG_NUM1; 170 4'h2: data0 <= SEG_NUM2; 171 4'h3: data0 <= SEG_NUM3; 172 4'h4: data0 <= SEG_NUM4; 173 4'h5: data0 <= SEG_NUM5; 174 4'h6: data0 <= SEG_NUM6; 175 4'h7: data0 <= SEG_NUM7; 176 4'h8: data0 <= SEG_NUM8; 177 4'h9: data0 <= SEG_NUM9; 178 default:data0 <= SEG_NUM0; 179 endcase 180 /*****************************************/ 181 reg [6:0] data1; 182 always @ (posedge sys_clk) 183 case(cout[7:4]) //进行编码 中 184 4'h0: data1 <= SEG_NUM0; 185 4'h1: data1 <= SEG_NUM1; 186 4'h2: data1 <= SEG_NUM2; 187 4'h3: data1 <= SEG_NUM3; 188 4'h4: data1 <= SEG_NUM4; 189 4'h5: data1 <= SEG_NUM5; 190 4'h6: data1 <= SEG_NUM6; 191 4'h7: data1 <= SEG_NUM7; 192 4'h8: data1 <= SEG_NUM8; 193 4'h9: data1 <= SEG_NUM9; 194 default:data1 <= SEG_NUM0; 195 endcase 196 /*****************************************/ 197 reg [6:0] data2; 198 always @ (posedge sys_clk) 199 case(cout[3:0]) //进行编码 低 200 4'h0: data2 <= SEG_NUM0; 201 4'h1: data2 <= SEG_NUM1; 202 4'h2: data2 <= SEG_NUM2; 203 4'h3: data2 <= SEG_NUM3; 204 4'h4: data2 <= SEG_NUM4; 205 4'h5: data2 <= SEG_NUM5; 206 4'h6: data2 <= SEG_NUM6; 207 4'h7: data2 <= SEG_NUM7; 208 4'h8: data2 <= SEG_NUM8; 209 4'h9: data2 <= SEG_NUM9; 210 default:data2 <= SEG_NUM0; 211 endcase 212 /***********************************************/ 213 reg [1:0] num; 214 always @ (posedge sys_clk or negedge rst_n) 215 if(!rst_n) 216 num <= 2'd0; 217 else if(cnt == T5MS) 218 num <= num + 1'b1; 219 else if(num == 2'd3) 220 num <= 2'd0; 221 /***********************************************/ 222 reg [6:0] slec_duan; 223 always @ (posedge sys_clk) 224 case(num) 225 2'd0: slec_duan <= data0; 226 2'd1: slec_duan <= data1; 227 2'd2: slec_duan <= data2; 228 endcase 229 230 endmodule
adc0809_control.v模块和adc0809_top模块请看基于Verilog HDL的ADC0809CCN数据采样中的代码。
当代码写完之后,发现显示的数据与实际电压有点偏差,高了0.2V左右,后来我测试了一下ADC0809的工作电压是4.8V,不是5V,我想可能是因为跟这个参考电压有关,为了让显示的数据与实际测试尽量接近,可以在代码中进行校准,我在中四位cout[7:4]减2,低cout[3:0]加1,其结果还是比较接近实际值。