在单片机C语言中,我们经常用/10,%10这样的方法将数字转换为字符串,反过来字符串转数字就用乘法:*10。
1829除以10,商182余9,得到个位数9。
182再除以10,商18余2,得到十位数2。
18除以10,商1余8,得到千位数1和百位数8。
但是这种方法并不适合于FPGA。因为乘法器和除法器都比较庞大,如果用在for循环里面,最后编译出来的电路会非常复杂,搞不好会把整个fpga的资源全部用完。
实际上,根本就不需要乘除法,我们只用加减法和移位就能搞定。
数字本质上就是二进制码,字符串本质上就是BCD码。
例如数字18是:00010010
而字符串"18"的十六进制形式是0x31 0x38
把左边的3去掉,剩下的就是1和8,合起来就是BCD码 0001 1000
我们要把字符串转换成数字,就是要将BCD码转换成二进制码(binary,也叫BIN码)。
把数字转换成字符串,就是把二进制码转换成BCD码,然后每个数位前面添上3(0011)就可以了
BIN和BCD之间的互相转换有专门的算法。
BIN转BCD:由加法和8次左移位组成
https://my.eng.utah.edu/~nmcdonal/Tutorials/BCDTutorial/BCDConversion.html
BCD转BIN:反过来,由减法和8次右移位组成
https://embeddedthoughts.com/2016/06/01/bcd-to-binary-conversion-on-an-fpga/
由于算法非常简单,我们可以在FPGA中用组合逻辑来实现,单个时钟周期就可以直接得出结果。
不需要乘法器和除法器。不需要多个时钟周期。

在单片机C语言中,我们经常用/10,%10这样的方法将数字转换为字符串,反过来字符串转数字就用乘法:*10。1829除以10,商182余9,得到个位数9。182再除以10,商18余2,得到十位数2。18除以10,商1余8,得到千位数1和百位数8。但是这种方法并不适合于FPGA。因为乘法器和除法器都比较庞大,如果用在for循环里面,最后编译出来的电路会非常复杂,搞不好会把整个fpga的资源全部用完。实际上,根本就不需要乘除法,我们只用加减法和移位就能搞定。数字本质上就是二进制码,字符串本质上就是B
之前对串口各模块的设计都做了相关介绍。这里介绍串口屏的相关知识。 本次项目使用的串口屏型号是陶晶驰串口屏TJC3224T024_011,这个型号的串口屏的资料在官网可以找到。本文抛 引玉,简单介绍以便在本工程中更好的应用。 下图是该串口屏的实物图: 一般地,使用单片机或者嵌入式MCU控制串口屏,都会用到串口,同样地,在 FPGA 中实现也是类似,不过稍微复杂,具体代码设计过程中有以下问题需要...
字符串 能够用在系统任务(诸如$display和$monitor等)中作为变量, 字符串 的值可以像 数字 一样储存在寄存器中,也可以像对 数字 一样对 字符串 进行赋值,比较和拼接。 1.一条 字符串 不能占源代码的多行; 2. 字符串 可以包含下列列表中的扩展字符; 3.诸如$display和$monitor等系统任务中的打印 字符串 可以包含特殊的格式控制 字符串 ,如%b。 4.当 字符串 存储于寄存器中,每个字符要占8位,字符以ASCII代码形式存储。 Verilog HDL语言的 字符串 的定义和C语言不一样。在C语言中需要用而
Verilog 中的for循环和disable语句是可综合的,利用for循环,可以像编写软件代码那样实现一些算法。 测试环境:Vivado 2020.1 + XC7A35T-2FGG484,晶振50MHz。 【StringManipulator.vh】 `define STRMANIP_STRLEN 1 `define STRMANIP_STRCAT 2 `define STRMANIP_ATOI 3 `define STRMANIP_ITOA 4 【StringManipulator.v】
module uart_send( input sys_clk, //系统时钟 input sys_rst_n, //系统复位,低电平有效 output reg uart_txd //UART发送端口 //pa...
1.整数赋值 按照 Verilog 2005的标准:0-9、a-f、z、x称作 数字 位(digit); 表示 数字 正负的’+‘和’-‘视作一元操作符(unary operator); 常说的二进制、八进制、十进制、十六进制称作 数字 的基(base); 其在 Verilog 中的表示’b’、‘o’、‘d’、'h’称作基格式(base format)字符; 表示常数的bit数称作size。 Verilog 使用到的字...
wire bps_start1,bps_start2; //接收到数据后,波特率时钟启动信号置位 wire clk_bps1,clk_bps2; // clk_bps_r高电平为接收数据位的中间采样点,同时也作为发送数据的数据改变点 wire[7:0] rx_data; //接收数据寄存器,保存直至下一个数据来到 wire rx_int; //接收数据中断信号,接收到数据期间始终为高电平 //---------------------------------------------------- //下面的四个模块中,speed_rx和speed_tx是两个完全独立的硬件模块,可称之为逻辑复制 //(不是资源共享,和软件中的同一个子程序调用不能混为一谈) //////////////////////////////////////////// speed_select speed_rx( .clk(clk), //波特率选择模块 .rst_n(rst_n), .bps_start(bps_start1), .clk_bps(clk_bps1) my_uart_rx my_uart_rx( .clk(clk), //接收数据模块 .rst_n(rst_n), .rs232_rx(rs232_rx), .rx_data(rx_data), .rx_int(rx_int), .clk_bps(clk_bps1), .bps_start(bps_start1) /////////////////////////////////////////// speed_select speed_tx( .clk(clk), //波特率选择模块 .rst_n(rst_n), .bps_start(bps_start2), .clk_bps(clk_bps2) my_uart_tx my_uart_tx( .clk(clk), //发送数据模块 .rst_n(rst_n), .rx_data(rx_data), .rx_int(rx_int), .rs232_tx(rs232_tx), .clk_bps(clk_bps2), .bps_start(bps_start2) endmodule module key_debounce( //按键消抖 input sys_clk, //外部50M时钟 input sys_rst_n, //外部复位信号,低有效 input [3:0] key, //外部按键输入 output reg k.