社区导航

 

搜索
查看: 22362|回复: 51

[原创] 【FPGA助学系列-12864显示的verilog实现】

  [复制链接]

6938

TA的帖子

17

TA的资源

版主

Rank: 6Rank: 6

发表于 2013-11-14 22:56 | 显示全部楼层 |阅读模式
12864是手中比较常用的LCD显示屏。今天在助学板子上试一下12864,板子上没有12864的接口,需要自己设计一个。这里使用8根数据线加E、R/W、RS三根控制线。要输入显示的数据在此被设置为固定数值。
  1. /*************************************************************

  2. *************************************************************/

  3. module lcd12864(
  4. clock, //系统时钟输入
  5. reset_n, //系统复位输入
  6. //in_data, //输入的要显示的数据
  7. LCD_RS, //LCD的寄存器选择输出信号
  8. LCD_RW, //LCD的读、写操作选择输出信号
  9. LCD_E, //LCD使能信号
  10. lcd_data, //LCD的数据总线(不进行读操作,故为输出)
  11. );
  12. input clock;
  13. input reset_n;
  14. //input in_data;
  15. output reg LCD_RS; //LCD的寄存器选择输出信号
  16. output LCD_RW; //LCD的读、写操作选择输出信号
  17. output LCD_E; //LCD使能信号
  18. output reg [7:0]lcd_data; //LCD的数据总线(不进行读操作,故为输出)
  19. reg [31:0] in_data = 32'd2294967296;
  20. // wire [31:0] in_data;
  21. reg clock_lcd; //LCD时钟信号
  22. reg [15:0]cnt; // CLK频率为50MHz, 产生LCD时钟信号, 10Hz
  23. always @(posedge clock or negedge reset_n)
  24. begin
  25. if (!reset_n)
  26. begin
  27. cnt <= 16'b0;clock_lcd <= 0;
  28. end
  29. else if(cnt == 49999)
  30. begin
  31. cnt <= 0;clock_lcd <= ~clock_lcd;
  32. end
  33. else cnt <= cnt +1'b1;
  34. end
  35. /*******************************************************************

  36. *********************************************************************/
  37. reg [8:0] state; //State Machine code
  38. parameter IDLE = 9'b00000000; //初始状态,下一个状态为CLEAR
  39. parameter SETFUNCTION = 9'b00000001; //功能设置:8位数据接口
  40. parameter SETFUNCTION2 = 9'b00000010;
  41. parameter SWITCHMODE = 9'b00000100; //显示开关控制:开显示,光标和闪烁关闭
  42. parameter CLEAR = 9'b00001000; //清屏
  43. parameter SETMODE = 9'b00010000; //输入方式设置:数据读写操作后,地址自动加一/画面不动
  44. parameter SETDDRAM = 9'b00100000; //设置DDRAM的地址:第一行起始为0x80/第二行为0x90
  45. parameter WRITERAM = 9'b01000000; //数据写入DDRAM相应的地址
  46. parameter STOP = 9'b10000000; //LCD操作完毕,释放其控制
  47. wire[7:0] disp_1,disp_2,disp_3,disp_4,disp_5,disp_6,disp_7,disp_8,disp_9,disp_10;
  48. //+8'h30为转换为ASCII
  49. assign disp_1 =in_data/32'd1000000000+8'h30;
  50. assign disp_2 =in_data%32'd1000000000/32'd100000000+8'h30; //1011 1110 1011 1100 0010 0000 000
  51. assign disp_3 =in_data%32'd100000000/32'd10000000+8'h30; //1001 1000 1001 0110 1000 0000
  52. assign disp_4 =in_data%32'd10000000/32'd1000000+8'h30; //1111 0100 0010 0100 0000
  53. assign disp_5 =in_data%32'd1000000/32'd100000+8'h30; //1100 0011 0101 0000 0
  54. assign disp_6 =in_data%32'd100000/32'd10000+8'h30; //1001 1100 0100 00
  55. assign disp_7 =in_data%32'd10000/32'd1000+8'h30;
  56. assign disp_8 =in_data%32'd1000/32'd100+8'h30;
  57. assign disp_9 =in_data%32'd100/32'd10+8'h30;
  58. assign disp_10 =in_data%32'd10+8'h30;
  59. reg flag; //标志位,LCD操作完毕为0
  60. reg [5:0] char_cnt;
  61. reg [7:0] data_disp;

  62. assign LCD_RW = 1'b0; //没有读操作,R/W信号始终为低电平

  63. assign LCD_E = (flag == 1)?clock_lcd:1'b0; //E信号出现高电平以及下降沿的时刻与LCD时钟相同

  64. always @(posedge clock_lcd or negedge reset_n) //只有在写数据操作时,RS信号才为高电平,其余为低电平

  65. begin
  66. if(!reset_n)
  67. LCD_RS <= 1'b0;
  68. else if(state == WRITERAM) //写数据
  69. LCD_RS <= 1'b1;
  70. else
  71. LCD_RS <= 1'b0; //写指令
  72. end
  73. /**************************************************************************
  74. // State Machine
  75. **************************************************************************/

  76. always @(posedge clock_lcd or negedge reset_n)

  77. begin
  78. if(!reset_n)
  79. begin
  80. state <= IDLE;
  81. lcd_data <= 8'bzzzzzzzz;
  82. char_cnt <= 5'b0;
  83. flag <= 1'b1;
  84. end
  85. else
  86. begin
  87. case(state)
  88. IDLE:
  89. begin
  90. state <= SETFUNCTION;
  91. lcd_data <= 8'bzzzzzzzz;
  92. end
  93. SETFUNCTION:
  94. begin
  95. state <= SETFUNCTION2;
  96. lcd_data <= 8'h30; // 8-bit 控制界面,基本指令集动作
  97. end
  98. SETFUNCTION2:
  99. begin
  100. state <= SWITCHMODE;
  101. lcd_data <= 8'h30; // 清屏
  102. end
  103. SWITCHMODE:
  104. begin
  105. state <= CLEAR;
  106. lcd_data <= 8'h0c; // 显示开关:开显示,光标和闪烁关闭
  107. end
  108. CLEAR:
  109. begin
  110. state <= SETMODE;
  111. lcd_data <= 8'h01;
  112. end
  113. SETMODE:
  114. begin
  115. state <= SETDDRAM;
  116. lcd_data <= 8'h06; // 输入方式设置: 数据读写后,地址自动加1,画面不动
  117. end
  118. SETDDRAM:
  119. begin
  120. state <= WRITERAM;
  121. if(char_cnt == 0) //如果显示的是第一个字符,则设置第一行的首字符地址
  122. begin
  123. lcd_data <= 8'h80; //Line1
  124. end
  125. else if(char_cnt ==16)//第二次设置时,是设置第二行的首字符地址
  126. begin
  127. lcd_data <= 8'h90;
  128. end
  129. else if(char_cnt == 32)
  130. begin
  131. lcd_data <= 8'h88;
  132. end
  133. else if(char_cnt == 48)
  134. begin
  135. lcd_data <= 8'h98;
  136. end
  137. end
  138. WRITERAM:
  139. begin
  140. if(char_cnt <= 15)
  141. begin
  142. char_cnt <= char_cnt + 1'b1;
  143. lcd_data <= data_disp;
  144. if( char_cnt == 15 )
  145. state <= SETDDRAM;
  146. else
  147. state <= WRITERAM;
  148. end
  149. else if( char_cnt >= 16 && char_cnt <= 31)
  150. begin
  151. lcd_data <= data_disp;
  152. state <= WRITERAM;
  153. char_cnt <= char_cnt + 1'b1;
  154. if( char_cnt == 31 ) //返回SETDDRAM修改写地址
  155. state <= SETDDRAM;
  156. else
  157. state <= WRITERAM; //
  158. end
  159. else if(char_cnt >= 32 && char_cnt <= 47)
  160. begin
  161. lcd_data <= data_disp;
  162. state <= WRITERAM;
  163. char_cnt <= char_cnt + 1'b1;
  164. if( char_cnt == 47 )
  165. state <= SETDDRAM;
  166. else
  167. state <= WRITERAM;
  168. end
  169. else if(char_cnt >= 48 && char_cnt <= 63)
  170. begin
  171. lcd_data <= data_disp;
  172. state <= WRITERAM;
  173. char_cnt <= char_cnt + 1'b1;
  174. if( char_cnt == 63 )
  175. state <= SETDDRAM;
  176. else
  177. state <= WRITERAM;
  178. end
  179. end
  180. STOP: state <= STOP;
  181. default: state <= IDLE;
  182. endcase
  183. end
  184. end

  185. always @(char_cnt) //输出的字符

  186. begin
  187. case (char_cnt)
  188. 6'd0: data_disp <= 8'h20;
  189. 6'd1: data_disp <= 8'h20; //
  190. 6'd2: data_disp <= 8'hB5;
  191. 6'd3: data_disp <= 8'hE7; //
  192. 6'd4: data_disp <= 8'hD7;
  193. 6'd5: data_disp <= 8'hD3; //
  194. 6'd6: data_disp <= 8'hB9;
  195. 6'd7: data_disp <= 8'hA4; //
  196. 6'd8: data_disp <= 8'hB3;
  197. 6'd9: data_disp <= 8'hCC;
  198. 6'd10: data_disp <= 8'hCA;
  199. 6'd11: data_disp <= 8'hC0;
  200. 6'd12: data_disp <= 8'hBD;
  201. 6'd13: data_disp <= 8'hE7;
  202. 6'd14: data_disp <= 8'h20;
  203. 6'd15: data_disp <= 8'h20;
  204. 6'd16: data_disp <= 1;
  205. 6'd17: data_disp <= 1;
  206. 6'd18: data_disp <= 1;
  207. 6'd19: data_disp <= 1;
  208. 6'd20: data_disp <= "E";
  209. 6'd21: data_disp <= "E";
  210. 6'd22: data_disp <= "W";
  211. 6'd23: data_disp <= "O";
  212. 6'd24: data_disp <= "R";
  213. 6'd25: data_disp <= "L";
  214. 6'd26: data_disp <= "D";
  215. 6'd27: data_disp <= 1;
  216. 6'd28: data_disp <= 1;
  217. 6'd29: data_disp <= 1;
  218. 6'd30: data_disp <= 1;
  219. 6'd31: data_disp <= 1;
  220. 6'd32: data_disp <= "F";
  221. 6'd33: data_disp <= "P";
  222. 6'd34: data_disp <= "G";
  223. 6'd35: data_disp <= "A";
  224. 6'd36: data_disp <= 8'hD6;
  225. 6'd37: data_disp <= 8'hFA;
  226. 6'd38: data_disp <= 8'hD1;
  227. 6'd39: data_disp <= 8'hA7;
  228. 6'd40: data_disp <= 8'hCF;
  229. 6'd41: data_disp <= 8'hB5;
  230. 6'd42: data_disp <= 8'hC1;
  231. 6'd43: data_disp <= 8'hD0;
  232. 6'd44: data_disp <= 8'h20;
  233. 6'd45: data_disp <= 8'h20;
  234. 6'd46: data_disp <= 8'h20;
  235. 6'd47: data_disp <= 8'h20;
  236. 6'd48: data_disp <= disp_1;
  237. 6'd49: data_disp <= disp_2; //
  238. 6'd50: data_disp <= disp_3;
  239. 6'd51: data_disp <= disp_4;
  240. 6'd52: data_disp <= disp_5;
  241. 6'd53: data_disp <= disp_6;
  242. 6'd54: data_disp <= disp_7;
  243. 6'd55: data_disp <= disp_8;
  244. 6'd56: data_disp <= disp_9;
  245. 6'd57: data_disp <= disp_10;
  246. 6'd58: data_disp <= 8'h20;
  247. 6'd59: data_disp <= 8'h20;
  248. 6'd60: data_disp <= 8'h20;
  249. 6'd61: data_disp <= 8'h20;
  250. 6'd62: data_disp <= 8'h20;
  251. 6'd63: data_disp <= 8'h20;
  252. //default : data_disp <= 8'd20;
  253. endcase
  254. end

  255. endmodule

复制代码
[ 本帖最后由 白丁 于 2013-11-14 23:03 编辑 ]
此帖出自FPGA/CPLD论坛
WP_20131114_007.jpg
WP_20131114_007.jpg
WP_20131114_009.jpg

评分

2

查看全部评分



回复

使用道具 举报

3003

TA的帖子

260

TA的资源

五彩晶圆(高级)

Rank: 9Rank: 9Rank: 9

荣誉会员勋章测评达人

发表于 2013-11-15 12:32 | 显示全部楼层
果断收藏,好东西啊,等忙完了,试试FPGA驱动12864.


回复

使用道具 举报

24

TA的帖子

4

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2013-11-15 17:26 | 显示全部楼层
挺牛逼了楼主


回复

使用道具 举报

118

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2013-11-15 18:21 | 显示全部楼层
其实这样显示,很不方便的。
就是说如果现在显示的是“EEWOLD”,要把它转为HELLO!,就要改六次(分别是六行代码的字符)。
不像C语言那样,定义字符数组,一次改好。

点评

那就定义字符串,按位显示  详情 回复 发表于 2013-11-15 18:51


回复

使用道具 举报

6938

TA的帖子

17

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2013-11-15 18:51 | 显示全部楼层

回复 4楼k331922164 的帖子

那就定义字符串,按位显示

点评

在这里,verilog比VHDL方便,有隐式的类型转换,VHDL要自己写个函数。  详情 回复 发表于 2013-11-15 18:55


回复

使用道具 举报

118

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2013-11-15 18:55 | 显示全部楼层

回复 5楼白丁 的帖子

在这里,verilog比VHDL方便,有隐式的类型转换,VHDL要自己写个函数。

点评

:shy:  详情 回复 发表于 2013-12-14 10:32


回复

使用道具 举报

821

TA的帖子

0

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

荣誉会员勋章

发表于 2013-11-15 23:06 | 显示全部楼层
提供一个思路。

用户显示需求 <-> 双口RAM  <-> 12864控制逻辑 <-> 12864

这样代码就有实用意义了。

点评

非常感谢提供思路  详情 回复 发表于 2013-11-15 23:07


回复

使用道具 举报

6938

TA的帖子

17

TA的资源

版主

Rank: 6Rank: 6

 楼主| 发表于 2013-11-15 23:07 | 显示全部楼层

回复 7楼deweyled 的帖子

非常感谢提供思路
training


回复

使用道具 举报

621

TA的帖子

0

TA的资源

五彩晶圆(初级)

Rank: 7Rank: 7Rank: 7

荣誉会员勋章

发表于 2013-11-16 00:14 | 显示全部楼层

经典的显示思路!发挥FPGA的绝对优势!!
用户显示需求(API) <-> 双口RAM 12864控制逻辑(HAL Drivers) <-> 12864(HardWare)
赞一个!!
Net:Wxeda.taobao.com
QQ:1035868547
Blog:http://home.eeworld.com.cn/space-uid-390804.html


回复

使用道具 举报

11

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2013-11-17 21:25 | 显示全部楼层


回复

使用道具 举报

11

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2013-11-17 21:25 | 显示全部楼层


回复

使用道具 举报

6552

TA的帖子

8

TA的资源

版主

Rank: 6Rank: 6

发表于 2013-11-17 23:19 | 显示全部楼层
  写的不错

但还是要注意发挥fpga的长处哦
生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰


回复

使用道具 举报

6552

TA的帖子

8

TA的资源

版主

Rank: 6Rank: 6

发表于 2013-11-17 23:21 | 显示全部楼层
kdy给的思路非常好,这就是所谓的 方法和思路, 往往比具体的实现更有价值
生活就是油盐酱醋再加一点糖,快活就是一天到晚乐呵呵的忙
===================================
做一个简单的人,踏实而务实,不沉溺幻想,不庸人自扰


回复

使用道具 举报

45

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2013-11-25 00:47 | 显示全部楼层

FPGA 12864

想法很好 不晓得实际怎么样


回复

使用道具 举报

41

TA的帖子

0

TA的资源

一粒金砂(中级)

Rank: 2

发表于 2013-12-10 09:48 | 显示全部楼层
学习了,,fpga还没入门


回复

使用道具 举报

8

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2013-12-14 10:32 | 显示全部楼层

回复 6楼k331922164 的帖子



回复

使用道具 举报

789

TA的帖子

0

TA的资源

一粒金砂(高级)

Rank: 3Rank: 3

发表于 2013-12-26 12:36 | 显示全部楼层
好东西  支持 一下
我从不担心我努力了不优秀,只担心优秀的人都比我更努力。如果你无法忍受孤独,就不要追逐梦想。每一个优秀的人,都有一段沉默的时光。在那一段时光,你付出了很多努力,忍受孤独和寂寞,不抱怨不诉苦,最后渡过了这


回复

使用道具 举报

4

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2014-4-4 23:13 | 显示全部楼层
很稳定!!为了让自己写的代码运行稳定应注意哪些基本事项呢


回复

使用道具 举报

2

TA的帖子

0

TA的资源

一粒金砂(初级)

Rank: 1

发表于 2014-4-27 22:23 | 显示全部楼层
KANKAN


回复

使用道具 举报

499

TA的帖子

0

TA的资源

五彩晶圆(中级)

Rank: 8Rank: 8

发表于 2014-6-16 11:28 | 显示全部楼层
跟着楼主学习了,刚开始接触VHDL,EP1C6~~


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

关闭

站长推荐上一条 1/7 下一条

  • 论坛活动 E手掌握

    扫码关注
    EEWORLD 官方微信

  • EE福利  唾手可得

    扫码关注
    EE福利 唾手可得

Archiver|手机版|小黑屋|电子工程世界 ( 京ICP证 060456 )

GMT+8, 2020-5-26 18:15 , Processed in 0.609722 second(s), 43 queries , Gzip On, MemCache On.

快速回复 返回顶部 返回列表