[{"content":"Welcome to Hugo theme Stack. This is your first post. Edit or delete it, then start writing!\nFor more information about this theme, check the documentation: https://docs.stack.jimmycai.com/\nWant a site like this? Check out hugo-theme-stack-stater\n Photo by Pawel Czerwinski on Unsplash\n ","date":"2022-03-06T00:00:00Z","image":"https://swetycore-github-io.vercel.app/p/hello-world/cover_hud7e36f7e20e71be184458283bdae4646_55974_120x120_fill_q75_box_smart1.jpg","permalink":"https://swetycore-github-io.vercel.app/p/hello-world/","title":"Hello World"},{"content":"Welcome to Hugo theme Stack. This is your first post. Edit or delete it, then start writing!\nFor more information about this theme, check the documentation: https://docs.stack.jimmycai.com/\nWant a site like this? Check out hugo-theme-stack-stater\n Photo by Pawel Czerwinski on Unsplash\n ","date":"2022-03-06T00:00:00Z","image":"https://swetycore-github-io.vercel.app/p/hello-world/cover_hud7e36f7e20e71be184458283bdae4646_55974_120x120_fill_q75_box_smart1.jpg","permalink":"https://swetycore-github-io.vercel.app/p/hello-world/","title":"Hello World"},{"content":"对于小脚丫驱动 OLED12832（SSD1306）代码的研究笔记。  内容为个人理解，不一定正确。  1. 数据手册 SSD1306数据手册/SSD1306规格书与控制芯片手册.zip · SwetyCore/个人网盘01 - Gitee.com\n2. 分析 连线    引脚 作用     oled_dcn 这是数据/命令控制引脚。当它被拉高(即连接到VDD)，数据D[7:0]作为数据处理。当它被拉低时，D[7:0]处的数据将被传输到命令寄存器。在I2C模式下，该引脚作为SA0来选择从地址。当选择三线串行接口时，此引脚必须连接到VSS。具体与单片机接口信号的关系请参考定时特性。   oled_dat    oled_csn 这个引脚是芯片选择输入。(低电平有效)    1 2 3 4 5 6 7 8 9  input\tclk,\t//12MHz系统时钟 \tinput\trst_n,\t//系统复位，低有效 \tinput [7:0]\tdata,\t// \toutput\treg\toled_csn,\t//OLCD液晶屏使能 \toutput\treg\toled_rst,\t//OLCD液晶屏复位 \toutput\treg\toled_dcn,\t//OLCD数据指令控制 \toutput\treg\toled_clk,\t//OLCD时钟信号 \toutput\treg\toled_dat\t//OLCD数据信号   变量对照表    变量名 作用     INIT_DEPTH 初始化的命令的数量   IDLE，MAIN，INIT，SCAN，WRITE ， DELAY 模块工作状态（值）   HIGH/LOW，DATA/CMD 高/低电平，数据/指令选择   [7:0] cmd [24:0] 存储初始化屏幕指令   [39:0] mem [122:0]; 存储 5*8 字库   [7:0]\ty_p，x_ph，x_pl; 定位列页地址，定位行地址低位，定位行地址高位   [(8*21-1):0] char; 存储要显示的字   [7:0]\tnum, char_reg; 要显示的字数量，？将要发送到oled的数据   [4:0]\tcnt_main, cnt_init, cnt_scan, cnt_write; 各种模块工作状态的子状态（名)   [15:0]\tnum_delay, cnt_delay, cnt; delay计数，delay设定值，指令发送计数   [5:0] state, state_back; 模块工作状态（名），执行完后要回到的状态        模块状态机分析   空闲(idle状态) 各种变量的初始化\n1 2 3 4 5 6 7 8  IDLE:begin cnt_main \u0026lt;= 1\u0026#39;b0; cnt_init \u0026lt;= 1\u0026#39;b0; cnt_scan \u0026lt;= 1\u0026#39;b0; cnt_write \u0026lt;= 1\u0026#39;b0; y_p \u0026lt;= 1\u0026#39;b0; x_ph \u0026lt;= 1\u0026#39;b0; x_pl \u0026lt;= 1\u0026#39;b0; num \u0026lt;= 1\u0026#39;b0; char \u0026lt;= 1\u0026#39;b0; char_reg \u0026lt;= 1\u0026#39;b0; num_delay \u0026lt;= 16\u0026#39;d5; cnt_delay \u0026lt;= 1\u0026#39;b0; cnt \u0026lt;= 1\u0026#39;b0; oled_csn \u0026lt;= HIGH; oled_rst \u0026lt;= HIGH; oled_dcn \u0026lt;= CMD; oled_clk \u0026lt;= HIGH; oled_dat \u0026lt;= LOW; state \u0026lt;= MAIN; state_back \u0026lt;= MAIN; end     屏幕初始化( init 状态)   1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23  INIT:begin\t//初始化状态 \tcase(cnt_init) 5\u0026#39;d0:\tbegin oled_rst \u0026lt;= LOW; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end\t//复位有效 \t//rst 引脚拉低，进入下一个状态。 \t5\u0026#39;d1:\tbegin num_delay \u0026lt;= 16\u0026#39;d25000; state \u0026lt;= DELAY; state_back \u0026lt;= INIT; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end\t//延时大于3us \t5\u0026#39;d2:\tbegin oled_rst \u0026lt;= HIGH; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end\t//复位恢复 \t//rst 拉高 \t5\u0026#39;d3:\tbegin num_delay \u0026lt;= 16\u0026#39;d25000; state \u0026lt;= DELAY; state_back \u0026lt;= INIT; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end\t//延时大于220us \t5\u0026#39;d4:\tbegin //发送data \tif(cnt\u0026gt;=INIT_DEPTH) begin\t//当25条指令及数据发出后，配置完成 cnt \u0026lt;= 1\u0026#39;b0; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end else begin\tcnt \u0026lt;= cnt + 1\u0026#39;b1; num_delay \u0026lt;= 16\u0026#39;d5; oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= cmd[cnt]; state \u0026lt;= WRITE; state_back \u0026lt;= INIT; end end 5\u0026#39;d5:\tbegin cnt_init \u0026lt;= 1\u0026#39;b0; state \u0026lt;= MAIN; end\t//初始化完成，返回MAIN状态 \tdefault: state \u0026lt;= IDLE; endcase end     Main状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23  SCAN:begin\t//刷屏状态，从RAM中读取数据刷屏 \tif(cnt_scan == 5\u0026#39;d11) begin if(num) cnt_scan \u0026lt;= 5\u0026#39;d3; else cnt_scan \u0026lt;= cnt_scan + 1\u0026#39;b1; end else if(cnt_scan == 5\u0026#39;d12) cnt_scan \u0026lt;= 1\u0026#39;b0; else cnt_scan \u0026lt;= cnt_scan + 1\u0026#39;b1; case(cnt_scan) 5\u0026#39;d 0:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= y_p; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位列页地址 \t5\u0026#39;d 1:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= x_pl; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位行地址低位 \t5\u0026#39;d 2:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= x_ph; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位行地址高位  5\u0026#39;d 3:\tbegin num \u0026lt;= num - 1\u0026#39;b1;end 5\u0026#39;d 4:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8 \t5\u0026#39;d 5:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8 \t5\u0026#39;d 6:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8 \t5\u0026#39;d 7:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][39:32]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d 8:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][31:24]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d 9:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][23:16]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d10:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][15: 8]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d11:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][ 7: 0]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d12:\tbegin state \u0026lt;= MAIN; end default: state \u0026lt;= IDLE; endcase     end ```    Delay状态？ 1 2 3 4 5 6  DELAY:begin\t//延时状态 \tif(cnt_delay \u0026gt;= num_delay) begin cnt_delay \u0026lt;= 16\u0026#39;d0; state \u0026lt;= state_back; end else cnt_delay \u0026lt;= cnt_delay + 1\u0026#39;b1; end default:state \u0026lt;= IDLE;     Write状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25  WRITE:begin\t//WRITE状态，将数据按照SPI时序发送给屏幕 \tif(cnt_write \u0026gt;= 5\u0026#39;d17) cnt_write \u0026lt;= 1\u0026#39;b0; else cnt_write \u0026lt;= cnt_write + 1\u0026#39;b1; case(cnt_write) 5\u0026#39;d 0:\tbegin oled_csn \u0026lt;= LOW; end\t//9位数据最高位为命令数据控制位 \t5\u0026#39;d 1:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[7]; end\t//先发高位数据 \t5\u0026#39;d 2:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d 3:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[6]; end 5\u0026#39;d 4:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d 5:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[5]; end 5\u0026#39;d 6:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d 7:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[4]; end 5\u0026#39;d 8:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d 9:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[3]; end 5\u0026#39;d10:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d11:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[2]; end 5\u0026#39;d12:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d13:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[1]; end 5\u0026#39;d14:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d15:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[0]; end\t//后发低位数据 \t5\u0026#39;d16:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d17:\tbegin oled_csn \u0026lt;= HIGH; state \u0026lt;= DELAY; end\t// \tdefault: state \u0026lt;= IDLE; endcase end   上升沿发送数据，共发送八位。\n  Scan 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24  SCAN:begin\t//刷屏状态，从RAM中读取数据刷屏 \tif(cnt_scan == 5\u0026#39;d11) begin if(num) cnt_scan \u0026lt;= 5\u0026#39;d3; else cnt_scan \u0026lt;= cnt_scan + 1\u0026#39;b1; end else if(cnt_scan == 5\u0026#39;d12) cnt_scan \u0026lt;= 1\u0026#39;b0; else cnt_scan \u0026lt;= cnt_scan + 1\u0026#39;b1; case(cnt_scan) 5\u0026#39;d 0:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= y_p; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位列页地址 \t5\u0026#39;d 1:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= x_pl; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位行地址低位 \t5\u0026#39;d 2:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= x_ph; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位行地址高位  5\u0026#39;d 3:\tbegin num \u0026lt;= num - 1\u0026#39;b1;end 5\u0026#39;d 4:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8 \t5\u0026#39;d 5:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8 \t5\u0026#39;d 6:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8(占三位？？？) \t5\u0026#39;d 7:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][39:32]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d 8:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][31:24]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d 9:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][23:16]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d10:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][15: 8]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d11:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][ 7: 0]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d12:\tbegin state \u0026lt;= MAIN; end default: state \u0026lt;= IDLE; endcase end   mem[char[(num*8)+:8]][ 7: 0] 的理解:\nmem为字库（二维列表）\nchar存有字符串八位二进制 ASCI 表示\n假设 char 为\u0026quot;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;-\u0026quot; (16个“ - ”)\n“-”的asci码为45 对应 mem[ 45] = {8'h08, 8'h08, 8'h08, 8'h08, 8'h08}; // 45 -\n此时 num 为16，[(num*8)+:8] 即为从 16*8 位置开始，取8位，刚好是 45 。\n然后 num 逐次减一直至取完第一个字符的 ASCI 码。\n  3. 原代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288  module oled12832 ( input\tclk,\t//12MHz系统时钟 \tinput\trst_n,\t//系统复位，低有效 \tinput [7:0]\tdata,\t// \toutput\treg\toled_csn,\t//OLCD液晶屏使能 \toutput\treg\toled_rst,\t//OLCD液晶屏复位 \toutput\treg\toled_dcn,\t//OLCD数据指令控制 \toutput\treg\toled_clk,\t//OLCD时钟信号 \toutput\treg\toled_dat\t//OLCD数据信号 ); localparam INIT_DEPTH = 16\u0026#39;d25; //LCD初始化的命令的数量 \tlocalparam IDLE = 6\u0026#39;h1, MAIN = 6\u0026#39;h2, INIT = 6\u0026#39;h4, SCAN = 6\u0026#39;h8, WRITE = 6\u0026#39;h10, DELAY = 6\u0026#39;h20; localparam HIGH\t= 1\u0026#39;b1, LOW = 1\u0026#39;b0; localparam DATA\t= 1\u0026#39;b1, CMD = 1\u0026#39;b0; reg [7:0] cmd [24:0]; reg [39:0] mem [122:0]; reg\t[7:0]\ty_p, x_ph, x_pl; reg\t[(8*21-1):0] char; reg\t[7:0]\tnum, char_reg;\t// \treg\t[4:0]\tcnt_main, cnt_init, cnt_scan, cnt_write; reg\t[15:0]\tnum_delay, cnt_delay, cnt; reg\t[5:0] state, state_back; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin cnt_main \u0026lt;= 1\u0026#39;b0; cnt_init \u0026lt;= 1\u0026#39;b0; cnt_scan \u0026lt;= 1\u0026#39;b0; cnt_write \u0026lt;= 1\u0026#39;b0; y_p \u0026lt;= 1\u0026#39;b0; x_ph \u0026lt;= 1\u0026#39;b0; x_pl \u0026lt;= 1\u0026#39;b0; num \u0026lt;= 1\u0026#39;b0; char \u0026lt;= 1\u0026#39;b0; char_reg \u0026lt;= 1\u0026#39;b0; num_delay \u0026lt;= 16\u0026#39;d5; cnt_delay \u0026lt;= 1\u0026#39;b0; cnt \u0026lt;= 1\u0026#39;b0; oled_csn \u0026lt;= HIGH; oled_rst \u0026lt;= HIGH; oled_dcn \u0026lt;= CMD; oled_clk \u0026lt;= HIGH; oled_dat \u0026lt;= LOW; state \u0026lt;= IDLE; state_back \u0026lt;= IDLE; end else begin case(state) IDLE:begin cnt_main \u0026lt;= 1\u0026#39;b0; cnt_init \u0026lt;= 1\u0026#39;b0; cnt_scan \u0026lt;= 1\u0026#39;b0; cnt_write \u0026lt;= 1\u0026#39;b0; y_p \u0026lt;= 1\u0026#39;b0; x_ph \u0026lt;= 1\u0026#39;b0; x_pl \u0026lt;= 1\u0026#39;b0; num \u0026lt;= 1\u0026#39;b0; char \u0026lt;= 1\u0026#39;b0; char_reg \u0026lt;= 1\u0026#39;b0; num_delay \u0026lt;= 16\u0026#39;d5; cnt_delay \u0026lt;= 1\u0026#39;b0; cnt \u0026lt;= 1\u0026#39;b0; oled_csn \u0026lt;= HIGH; oled_rst \u0026lt;= HIGH; oled_dcn \u0026lt;= CMD; oled_clk \u0026lt;= HIGH; oled_dat \u0026lt;= LOW; state \u0026lt;= MAIN; state_back \u0026lt;= MAIN; end MAIN:begin if(cnt_main \u0026gt;= 5\u0026#39;d6) cnt_main \u0026lt;= 5\u0026#39;d5; else cnt_main \u0026lt;= cnt_main + 1\u0026#39;b1; case(cnt_main)\t//MAIN状态 \t5\u0026#39;d0:\tbegin state \u0026lt;= INIT; end 5\u0026#39;d1:\tbegin y_p \u0026lt;= 8\u0026#39;hb0; x_ph \u0026lt;= 8\u0026#39;h10; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d16; char \u0026lt;= \u0026#34;----------------\u0026#34;;state \u0026lt;= SCAN; end 5\u0026#39;d2:\tbegin y_p \u0026lt;= 8\u0026#39;hb1; x_ph \u0026lt;= 8\u0026#39;h10; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d16; char \u0026lt;= \u0026#34; voltage: . V \u0026#34;;state \u0026lt;= SCAN; end 5\u0026#39;d3:\tbegin y_p \u0026lt;= 8\u0026#39;hb2; x_ph \u0026lt;= 8\u0026#39;h10; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d16; char \u0026lt;= \u0026#34; \u0026#34;;state \u0026lt;= SCAN; end 5\u0026#39;d4:\tbegin y_p \u0026lt;= 8\u0026#39;hb3; x_ph \u0026lt;= 8\u0026#39;h10; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d16; char \u0026lt;= \u0026#34;----------------\u0026#34;;state \u0026lt;= SCAN; end //5\u0026#39;d5:\tbegin y_p \u0026lt;= 8\u0026#39;hb0; x_ph \u0026lt;= 8\u0026#39;h15; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d 1; char \u0026lt;= data[3:0]; state \u0026lt;= SCAN; end \t//5\u0026#39;d5:\tbegin y_p \u0026lt;= 8\u0026#39;hb1; x_ph \u0026lt;= 8\u0026#39;h15; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d 3; char \u0026lt;={data[7:4],\u0026#34;.\u0026#34;data[3:0]}; state \u0026lt;= SCAN; end \t5\u0026#39;d5:\tbegin y_p \u0026lt;= 8\u0026#39;hb1; x_ph \u0026lt;= 8\u0026#39;h15; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d 1; char \u0026lt;=data[7:4]; state \u0026lt;= SCAN; end 5\u0026#39;d6:\tbegin y_p \u0026lt;= 8\u0026#39;hb1; x_ph \u0026lt;= 8\u0026#39;h16; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d 1; char \u0026lt;=data[3:0]; state \u0026lt;= SCAN; end //5\u0026#39;d6:\tbegin y_p \u0026lt;= 8\u0026#39;hb3; x_ph \u0026lt;= 8\u0026#39;h15; x_pl \u0026lt;= 8\u0026#39;h00; num \u0026lt;= 5\u0026#39;d 1; char \u0026lt;= \u0026#34;O\u0026#34;; state \u0026lt;= SCAN; end  default: state \u0026lt;= IDLE; endcase end INIT:begin\t//初始化状态 \tcase(cnt_init) 5\u0026#39;d0:\tbegin oled_rst \u0026lt;= LOW; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end\t//复位有效 \t5\u0026#39;d1:\tbegin num_delay \u0026lt;= 16\u0026#39;d25000; state \u0026lt;= DELAY; state_back \u0026lt;= INIT; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end\t//延时大于3us \t5\u0026#39;d2:\tbegin oled_rst \u0026lt;= HIGH; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end\t//复位恢复 \t5\u0026#39;d3:\tbegin num_delay \u0026lt;= 16\u0026#39;d25000; state \u0026lt;= DELAY; state_back \u0026lt;= INIT; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end\t//延时大于220us \t5\u0026#39;d4:\tbegin if(cnt\u0026gt;=INIT_DEPTH) begin\t//当25条指令及数据发出后，配置完成 \tcnt \u0026lt;= 1\u0026#39;b0; cnt_init \u0026lt;= cnt_init + 1\u0026#39;b1; end else begin\tcnt \u0026lt;= cnt + 1\u0026#39;b1; num_delay \u0026lt;= 16\u0026#39;d5; oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= cmd[cnt]; state \u0026lt;= WRITE; state_back \u0026lt;= INIT; end end 5\u0026#39;d5:\tbegin cnt_init \u0026lt;= 1\u0026#39;b0; state \u0026lt;= MAIN; end\t//初始化完成，返回MAIN状态 \tdefault: state \u0026lt;= IDLE; endcase end SCAN:begin\t//刷屏状态，从RAM中读取数据刷屏 \tif(cnt_scan == 5\u0026#39;d11) begin if(num) cnt_scan \u0026lt;= 5\u0026#39;d3; else cnt_scan \u0026lt;= cnt_scan + 1\u0026#39;b1; end else if(cnt_scan == 5\u0026#39;d12) cnt_scan \u0026lt;= 1\u0026#39;b0; else cnt_scan \u0026lt;= cnt_scan + 1\u0026#39;b1; case(cnt_scan) 5\u0026#39;d 0:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= y_p; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位列页地址 \t5\u0026#39;d 1:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= x_pl; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位行地址低位 \t5\u0026#39;d 2:\tbegin oled_dcn \u0026lt;= CMD; char_reg \u0026lt;= x_ph; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//定位行地址高位 \t5\u0026#39;d 3:\tbegin num \u0026lt;= num - 1\u0026#39;b1;end 5\u0026#39;d 4:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8 \t5\u0026#39;d 5:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8 \t5\u0026#39;d 6:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= 8\u0026#39;h00; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end\t//将5*8点阵编程8*8 \t5\u0026#39;d 7:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][39:32]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d 8:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][31:24]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d 9:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][23:16]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d10:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][15: 8]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d11:\tbegin oled_dcn \u0026lt;= DATA; char_reg \u0026lt;= mem[char[(num*8)+:8]][ 7: 0]; state \u0026lt;= WRITE; state_back \u0026lt;= SCAN; end 5\u0026#39;d12:\tbegin state \u0026lt;= MAIN; end default: state \u0026lt;= IDLE; endcase end WRITE:begin\t//WRITE状态，将数据按照SPI时序发送给屏幕 \tif(cnt_write \u0026gt;= 5\u0026#39;d17) cnt_write \u0026lt;= 1\u0026#39;b0; else cnt_write \u0026lt;= cnt_write + 1\u0026#39;b1; case(cnt_write) 5\u0026#39;d 0:\tbegin oled_csn \u0026lt;= LOW; end\t//9位数据最高位为命令数据控制位 \t5\u0026#39;d 1:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[7]; end\t//先发高位数据 \t5\u0026#39;d 2:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d 3:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[6]; end 5\u0026#39;d 4:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d 5:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[5]; end 5\u0026#39;d 6:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d 7:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[4]; end 5\u0026#39;d 8:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d 9:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[3]; end 5\u0026#39;d10:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d11:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[2]; end 5\u0026#39;d12:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d13:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[1]; end 5\u0026#39;d14:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d15:\tbegin oled_clk \u0026lt;= LOW; oled_dat \u0026lt;= char_reg[0]; end\t//后发低位数据 \t5\u0026#39;d16:\tbegin oled_clk \u0026lt;= HIGH; end 5\u0026#39;d17:\tbegin oled_csn \u0026lt;= HIGH; state \u0026lt;= DELAY; end\t// \tdefault: state \u0026lt;= IDLE; endcase end DELAY:begin\t//延时状态 \tif(cnt_delay \u0026gt;= num_delay) begin cnt_delay \u0026lt;= 16\u0026#39;d0; state \u0026lt;= state_back; end else cnt_delay \u0026lt;= cnt_delay + 1\u0026#39;b1; end default:state \u0026lt;= IDLE; endcase end end //OLED配置指令数据 \talways@(posedge rst_n) begin cmd[ 0] = {8\u0026#39;hae}; cmd[ 1] = {8\u0026#39;h00}; cmd[ 2] = {8\u0026#39;h10}; cmd[ 3] = {8\u0026#39;h00}; cmd[ 4] = {8\u0026#39;hb0}; cmd[ 5] = {8\u0026#39;h81}; cmd[ 6] = {8\u0026#39;hff}; cmd[ 7] = {8\u0026#39;ha1}; cmd[ 8] = {8\u0026#39;ha6}; cmd[ 9] = {8\u0026#39;ha8}; cmd[10] = {8\u0026#39;h1f}; cmd[11] = {8\u0026#39;hc8}; cmd[12] = {8\u0026#39;hd3}; cmd[13] = {8\u0026#39;h00}; cmd[14] = {8\u0026#39;hd5}; cmd[15] = {8\u0026#39;h80}; cmd[16] = {8\u0026#39;hd9}; cmd[17] = {8\u0026#39;h1f}; cmd[18] = {8\u0026#39;hda}; cmd[19] = {8\u0026#39;h00}; cmd[20] = {8\u0026#39;hdb}; cmd[21] = {8\u0026#39;h40}; cmd[22] = {8\u0026#39;h8d}; cmd[23] = {8\u0026#39;h14}; cmd[24] = {8\u0026#39;haf}; end //5*8点阵字库数据 \talways@(posedge rst_n) begin mem[ 0] = {8\u0026#39;h3E, 8\u0026#39;h51, 8\u0026#39;h49, 8\u0026#39;h45, 8\u0026#39;h3E}; // 48 0 \tmem[ 1] = {8\u0026#39;h00, 8\u0026#39;h42, 8\u0026#39;h7F, 8\u0026#39;h40, 8\u0026#39;h00}; // 49 1 \tmem[ 2] = {8\u0026#39;h42, 8\u0026#39;h61, 8\u0026#39;h51, 8\u0026#39;h49, 8\u0026#39;h46}; // 50 2 \tmem[ 3] = {8\u0026#39;h21, 8\u0026#39;h41, 8\u0026#39;h45, 8\u0026#39;h4B, 8\u0026#39;h31}; // 51 3 \tmem[ 4] = {8\u0026#39;h18, 8\u0026#39;h14, 8\u0026#39;h12, 8\u0026#39;h7F, 8\u0026#39;h10}; // 52 4 \tmem[ 5] = {8\u0026#39;h27, 8\u0026#39;h45, 8\u0026#39;h45, 8\u0026#39;h45, 8\u0026#39;h39}; // 53 5 \tmem[ 6] = {8\u0026#39;h3C, 8\u0026#39;h4A, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h30}; // 54 6 \tmem[ 7] = {8\u0026#39;h01, 8\u0026#39;h71, 8\u0026#39;h09, 8\u0026#39;h05, 8\u0026#39;h03}; // 55 7 \tmem[ 8] = {8\u0026#39;h36, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h36}; // 56 8 \tmem[ 9] = {8\u0026#39;h06, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h29, 8\u0026#39;h1E}; // 57 9 \tmem[ 10] = {8\u0026#39;h7C, 8\u0026#39;h12, 8\u0026#39;h11, 8\u0026#39;h12, 8\u0026#39;h7C}; // 65 A \tmem[ 11] = {8\u0026#39;h7F, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h36}; // 66 B \tmem[ 12] = {8\u0026#39;h3E, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h22}; // 67 C \tmem[ 13] = {8\u0026#39;h7F, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h22, 8\u0026#39;h1C}; // 68 D \tmem[ 14] = {8\u0026#39;h7F, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h41}; // 69 E \tmem[ 15] = {8\u0026#39;h7F, 8\u0026#39;h09, 8\u0026#39;h09, 8\u0026#39;h09, 8\u0026#39;h01}; // 70 F  mem[ 32] = {8\u0026#39;h00, 8\u0026#39;h00, 8\u0026#39;h00, 8\u0026#39;h00, 8\u0026#39;h00}; // 32 sp \tmem[ 33] = {8\u0026#39;h00, 8\u0026#39;h00, 8\u0026#39;h2f, 8\u0026#39;h00, 8\u0026#39;h00}; // 33 ! \tmem[ 34] = {8\u0026#39;h00, 8\u0026#39;h07, 8\u0026#39;h00, 8\u0026#39;h07, 8\u0026#39;h00}; // 34 \tmem[ 35] = {8\u0026#39;h14, 8\u0026#39;h7f, 8\u0026#39;h14, 8\u0026#39;h7f, 8\u0026#39;h14}; // 35 # \tmem[ 36] = {8\u0026#39;h24, 8\u0026#39;h2a, 8\u0026#39;h7f, 8\u0026#39;h2a, 8\u0026#39;h12}; // 36 $ \tmem[ 37] = {8\u0026#39;h62, 8\u0026#39;h64, 8\u0026#39;h08, 8\u0026#39;h13, 8\u0026#39;h23}; // 37 % \tmem[ 38] = {8\u0026#39;h36, 8\u0026#39;h49, 8\u0026#39;h55, 8\u0026#39;h22, 8\u0026#39;h50}; // 38 \u0026amp; \tmem[ 39] = {8\u0026#39;h00, 8\u0026#39;h05, 8\u0026#39;h03, 8\u0026#39;h00, 8\u0026#39;h00}; // 39 \u0026#39; \tmem[ 40] = {8\u0026#39;h00, 8\u0026#39;h1c, 8\u0026#39;h22, 8\u0026#39;h41, 8\u0026#39;h00}; // 40 ( \tmem[ 41] = {8\u0026#39;h00, 8\u0026#39;h41, 8\u0026#39;h22, 8\u0026#39;h1c, 8\u0026#39;h00}; // 41 ) \tmem[ 42] = {8\u0026#39;h14, 8\u0026#39;h08, 8\u0026#39;h3E, 8\u0026#39;h08, 8\u0026#39;h14}; // 42 * \tmem[ 43] = {8\u0026#39;h08, 8\u0026#39;h08, 8\u0026#39;h3E, 8\u0026#39;h08, 8\u0026#39;h08}; // 43 + \tmem[ 44] = {8\u0026#39;h00, 8\u0026#39;h00, 8\u0026#39;hA0, 8\u0026#39;h60, 8\u0026#39;h00}; // 44 , \tmem[ 45] = {8\u0026#39;h08, 8\u0026#39;h08, 8\u0026#39;h08, 8\u0026#39;h08, 8\u0026#39;h08}; // 45 - \tmem[ 46] = {8\u0026#39;h00, 8\u0026#39;h60, 8\u0026#39;h60, 8\u0026#39;h00, 8\u0026#39;h00}; // 46 . \tmem[ 47] = {8\u0026#39;h20, 8\u0026#39;h10, 8\u0026#39;h08, 8\u0026#39;h04, 8\u0026#39;h02}; // 47 / \tmem[ 48] = {8\u0026#39;h3E, 8\u0026#39;h51, 8\u0026#39;h49, 8\u0026#39;h45, 8\u0026#39;h3E}; // 48 0 \tmem[ 49] = {8\u0026#39;h00, 8\u0026#39;h42, 8\u0026#39;h7F, 8\u0026#39;h40, 8\u0026#39;h00}; // 49 1 \tmem[ 50] = {8\u0026#39;h42, 8\u0026#39;h61, 8\u0026#39;h51, 8\u0026#39;h49, 8\u0026#39;h46}; // 50 2 \tmem[ 51] = {8\u0026#39;h21, 8\u0026#39;h41, 8\u0026#39;h45, 8\u0026#39;h4B, 8\u0026#39;h31}; // 51 3 \tmem[ 52] = {8\u0026#39;h18, 8\u0026#39;h14, 8\u0026#39;h12, 8\u0026#39;h7F, 8\u0026#39;h10}; // 52 4 \tmem[ 53] = {8\u0026#39;h27, 8\u0026#39;h45, 8\u0026#39;h45, 8\u0026#39;h45, 8\u0026#39;h39}; // 53 5 \tmem[ 54] = {8\u0026#39;h3C, 8\u0026#39;h4A, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h30}; // 54 6 \tmem[ 55] = {8\u0026#39;h01, 8\u0026#39;h71, 8\u0026#39;h09, 8\u0026#39;h05, 8\u0026#39;h03}; // 55 7 \tmem[ 56] = {8\u0026#39;h36, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h36}; // 56 8 \tmem[ 57] = {8\u0026#39;h06, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h29, 8\u0026#39;h1E}; // 57 9 \tmem[ 58] = {8\u0026#39;h00, 8\u0026#39;h36, 8\u0026#39;h36, 8\u0026#39;h00, 8\u0026#39;h00}; // 58 : \tmem[ 59] = {8\u0026#39;h00, 8\u0026#39;h56, 8\u0026#39;h36, 8\u0026#39;h00, 8\u0026#39;h00}; // 59 ; \tmem[ 60] = {8\u0026#39;h08, 8\u0026#39;h14, 8\u0026#39;h22, 8\u0026#39;h41, 8\u0026#39;h00}; // 60 \u0026lt; \tmem[ 61] = {8\u0026#39;h14, 8\u0026#39;h14, 8\u0026#39;h14, 8\u0026#39;h14, 8\u0026#39;h14}; // 61 = \tmem[ 62] = {8\u0026#39;h00, 8\u0026#39;h41, 8\u0026#39;h22, 8\u0026#39;h14, 8\u0026#39;h08}; // 62 \u0026gt; \tmem[ 63] = {8\u0026#39;h02, 8\u0026#39;h01, 8\u0026#39;h51, 8\u0026#39;h09, 8\u0026#39;h06}; // 63 ? \tmem[ 64] = {8\u0026#39;h32, 8\u0026#39;h49, 8\u0026#39;h59, 8\u0026#39;h51, 8\u0026#39;h3E}; // 64 @ \tmem[ 65] = {8\u0026#39;h7C, 8\u0026#39;h12, 8\u0026#39;h11, 8\u0026#39;h12, 8\u0026#39;h7C}; // 65 A \tmem[ 66] = {8\u0026#39;h7F, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h36}; // 66 B \tmem[ 67] = {8\u0026#39;h3E, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h22}; // 67 C \tmem[ 68] = {8\u0026#39;h7F, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h22, 8\u0026#39;h1C}; // 68 D \tmem[ 69] = {8\u0026#39;h7F, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h41}; // 69 E \tmem[ 70] = {8\u0026#39;h7F, 8\u0026#39;h09, 8\u0026#39;h09, 8\u0026#39;h09, 8\u0026#39;h01}; // 70 F \tmem[ 71] = {8\u0026#39;h3E, 8\u0026#39;h41, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h7A}; // 71 G \tmem[ 72] = {8\u0026#39;h7F, 8\u0026#39;h08, 8\u0026#39;h08, 8\u0026#39;h08, 8\u0026#39;h7F}; // 72 H \tmem[ 73] = {8\u0026#39;h00, 8\u0026#39;h41, 8\u0026#39;h7F, 8\u0026#39;h41, 8\u0026#39;h00}; // 73 I \tmem[ 74] = {8\u0026#39;h20, 8\u0026#39;h40, 8\u0026#39;h41, 8\u0026#39;h3F, 8\u0026#39;h01}; // 74 J \tmem[ 75] = {8\u0026#39;h7F, 8\u0026#39;h08, 8\u0026#39;h14, 8\u0026#39;h22, 8\u0026#39;h41}; // 75 K \tmem[ 76] = {8\u0026#39;h7F, 8\u0026#39;h40, 8\u0026#39;h40, 8\u0026#39;h40, 8\u0026#39;h40}; // 76 L \tmem[ 77] = {8\u0026#39;h7F, 8\u0026#39;h02, 8\u0026#39;h0C, 8\u0026#39;h02, 8\u0026#39;h7F}; // 77 M \tmem[ 78] = {8\u0026#39;h7F, 8\u0026#39;h04, 8\u0026#39;h08, 8\u0026#39;h10, 8\u0026#39;h7F}; // 78 N \tmem[ 79] = {8\u0026#39;h3E, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h3E}; // 79 O \tmem[ 80] = {8\u0026#39;h7F, 8\u0026#39;h09, 8\u0026#39;h09, 8\u0026#39;h09, 8\u0026#39;h06}; // 80 P \tmem[ 81] = {8\u0026#39;h3E, 8\u0026#39;h41, 8\u0026#39;h51, 8\u0026#39;h21, 8\u0026#39;h5E}; // 81 Q \tmem[ 82] = {8\u0026#39;h7F, 8\u0026#39;h09, 8\u0026#39;h19, 8\u0026#39;h29, 8\u0026#39;h46}; // 82 R \tmem[ 83] = {8\u0026#39;h46, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h49, 8\u0026#39;h31}; // 83 S \tmem[ 84] = {8\u0026#39;h01, 8\u0026#39;h01, 8\u0026#39;h7F, 8\u0026#39;h01, 8\u0026#39;h01}; // 84 T \tmem[ 85] = {8\u0026#39;h3F, 8\u0026#39;h40, 8\u0026#39;h40, 8\u0026#39;h40, 8\u0026#39;h3F}; // 85 U \tmem[ 86] = {8\u0026#39;h1F, 8\u0026#39;h20, 8\u0026#39;h40, 8\u0026#39;h20, 8\u0026#39;h1F}; // 86 V \tmem[ 87] = {8\u0026#39;h3F, 8\u0026#39;h40, 8\u0026#39;h38, 8\u0026#39;h40, 8\u0026#39;h3F}; // 87 W \tmem[ 88] = {8\u0026#39;h63, 8\u0026#39;h14, 8\u0026#39;h08, 8\u0026#39;h14, 8\u0026#39;h63}; // 88 X \tmem[ 89] = {8\u0026#39;h07, 8\u0026#39;h08, 8\u0026#39;h70, 8\u0026#39;h08, 8\u0026#39;h07}; // 89 Y \tmem[ 90] = {8\u0026#39;h61, 8\u0026#39;h51, 8\u0026#39;h49, 8\u0026#39;h45, 8\u0026#39;h43}; // 90 Z \tmem[ 91] = {8\u0026#39;h00, 8\u0026#39;h7F, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h00}; // 91 [ \tmem[ 92] = {8\u0026#39;h55, 8\u0026#39;h2A, 8\u0026#39;h55, 8\u0026#39;h2A, 8\u0026#39;h55}; // 92 . \tmem[ 93] = {8\u0026#39;h00, 8\u0026#39;h41, 8\u0026#39;h41, 8\u0026#39;h7F, 8\u0026#39;h00}; // 93 ] \tmem[ 94] = {8\u0026#39;h04, 8\u0026#39;h02, 8\u0026#39;h01, 8\u0026#39;h02, 8\u0026#39;h04}; // 94 ^ \tmem[ 95] = {8\u0026#39;h40, 8\u0026#39;h40, 8\u0026#39;h40, 8\u0026#39;h40, 8\u0026#39;h40}; // 95 _ \tmem[ 96] = {8\u0026#39;h00, 8\u0026#39;h01, 8\u0026#39;h02, 8\u0026#39;h04, 8\u0026#39;h00}; // 96 \u0026#39; \tmem[ 97] = {8\u0026#39;h20, 8\u0026#39;h54, 8\u0026#39;h54, 8\u0026#39;h54, 8\u0026#39;h78}; // 97 a \tmem[ 98] = {8\u0026#39;h7F, 8\u0026#39;h48, 8\u0026#39;h44, 8\u0026#39;h44, 8\u0026#39;h38}; // 98 b \tmem[ 99] = {8\u0026#39;h38, 8\u0026#39;h44, 8\u0026#39;h44, 8\u0026#39;h44, 8\u0026#39;h20}; // 99 c \tmem[100] = {8\u0026#39;h38, 8\u0026#39;h44, 8\u0026#39;h44, 8\u0026#39;h48, 8\u0026#39;h7F}; // 100 d \tmem[101] = {8\u0026#39;h38, 8\u0026#39;h54, 8\u0026#39;h54, 8\u0026#39;h54, 8\u0026#39;h18}; // 101 e \tmem[102] = {8\u0026#39;h08, 8\u0026#39;h7E, 8\u0026#39;h09, 8\u0026#39;h01, 8\u0026#39;h02}; // 102 f \tmem[103] = {8\u0026#39;h18, 8\u0026#39;hA4, 8\u0026#39;hA4, 8\u0026#39;hA4, 8\u0026#39;h7C}; // 103 g \tmem[104] = {8\u0026#39;h7F, 8\u0026#39;h08, 8\u0026#39;h04, 8\u0026#39;h04, 8\u0026#39;h78}; // 104 h \tmem[105] = {8\u0026#39;h00, 8\u0026#39;h44, 8\u0026#39;h7D, 8\u0026#39;h40, 8\u0026#39;h00}; // 105 i \tmem[106] = {8\u0026#39;h40, 8\u0026#39;h80, 8\u0026#39;h84, 8\u0026#39;h7D, 8\u0026#39;h00}; // 106 j \tmem[107] = {8\u0026#39;h7F, 8\u0026#39;h10, 8\u0026#39;h28, 8\u0026#39;h44, 8\u0026#39;h00}; // 107 k \tmem[108] = {8\u0026#39;h00, 8\u0026#39;h41, 8\u0026#39;h7F, 8\u0026#39;h40, 8\u0026#39;h00}; // 108 l \tmem[109] = {8\u0026#39;h7C, 8\u0026#39;h04, 8\u0026#39;h18, 8\u0026#39;h04, 8\u0026#39;h78}; // 109 m \tmem[110] = {8\u0026#39;h7C, 8\u0026#39;h08, 8\u0026#39;h04, 8\u0026#39;h04, 8\u0026#39;h78}; // 110 n \tmem[111] = {8\u0026#39;h38, 8\u0026#39;h44, 8\u0026#39;h44, 8\u0026#39;h44, 8\u0026#39;h38}; // 111 o \tmem[112] = {8\u0026#39;hFC, 8\u0026#39;h24, 8\u0026#39;h24, 8\u0026#39;h24, 8\u0026#39;h18}; // 112 p \tmem[113] = {8\u0026#39;h18, 8\u0026#39;h24, 8\u0026#39;h24, 8\u0026#39;h18, 8\u0026#39;hFC}; // 113 q \tmem[114] = {8\u0026#39;h7C, 8\u0026#39;h08, 8\u0026#39;h04, 8\u0026#39;h04, 8\u0026#39;h08}; // 114 r \tmem[115] = {8\u0026#39;h48, 8\u0026#39;h54, 8\u0026#39;h54, 8\u0026#39;h54, 8\u0026#39;h20}; // 115 s \tmem[116] = {8\u0026#39;h04, 8\u0026#39;h3F, 8\u0026#39;h44, 8\u0026#39;h40, 8\u0026#39;h20}; // 116 t \tmem[117] = {8\u0026#39;h3C, 8\u0026#39;h40, 8\u0026#39;h40, 8\u0026#39;h20, 8\u0026#39;h7C}; // 117 u \tmem[118] = {8\u0026#39;h1C, 8\u0026#39;h20, 8\u0026#39;h40, 8\u0026#39;h20, 8\u0026#39;h1C}; // 118 v \tmem[119] = {8\u0026#39;h3C, 8\u0026#39;h40, 8\u0026#39;h30, 8\u0026#39;h40, 8\u0026#39;h3C}; // 119 w \tmem[120] = {8\u0026#39;h44, 8\u0026#39;h28, 8\u0026#39;h10, 8\u0026#39;h28, 8\u0026#39;h44}; // 120 x \tmem[121] = {8\u0026#39;h1C, 8\u0026#39;hA0, 8\u0026#39;hA0, 8\u0026#39;hA0, 8\u0026#39;h7C}; // 121 y \tmem[122] = {8\u0026#39;h44, 8\u0026#39;h64, 8\u0026#39;h54, 8\u0026#39;h4C, 8\u0026#39;h44}; // 122 z \tend endmodule   ","date":"2021-12-07T23:17:54Z","permalink":"https://swetycore-github-io.vercel.app/p/%E5%AF%B9%E4%BA%8E%E5%B0%8F%E8%84%9A%E4%B8%AB%E9%A9%B1%E5%8A%A8-oled12832ssd1306%E4%BB%A3%E7%A0%81%E7%9A%84%E7%A0%94%E7%A9%B6%E7%AC%94%E8%AE%B0/","title":"对于小脚丫驱动 OLED12832（SSD1306）代码的研究笔记"},{"content":"介绍  效果展示   介绍  显示时间 根据IP定位显示天气 利用Smart Config进行微信扫码联网    制作过程   材料表\n ESP32开发板 *1 母对母杜邦线 *7 2.0寸主控IC为ILI9225的TFT显示屏 *1 Micro USB数据线 *1    工具\n Arduino IDE Visual Studio Code Python3 环境 msys2 图片编辑工具（我这里用的是自带的画图） Img2Lcd 某宝客服赠送的工具 FontSmaller 字体文件子集化工具 FontLabTypeTool 付费软件    硬件连接表\n   ESP32 TFT屏幕     3V3 VCC   GND GND   25 RS   15 CS   14 CLK   13 SDA   26 EST      库文件\n1 2 3 4 5  #include \u0026lt;Arduino_GFX_Library.h\u0026gt;#include \u0026lt;ArduinoJson.h\u0026gt;#include \u0026lt;HTTPClient.h\u0026gt;#include \u0026lt;time.h\u0026gt;#include \u0026lt;SPI.h\u0026gt;    程序编写   WIFI连接\n在一般情况下，如果直接将WiFi的SSID和密码写入到代码中将不利于切换网络，因此我们使用WiFi Smart Config来进行配网，代码在Arduino的示例程序里找到。\n  时间同步\n由于ESP32断电并不会保存时间，因此每次上电都需要从网络获取时间。\n利用 configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);来同步时间，相关代码如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15  const char* ntpServer = \u0026#34;pool.ntp.org\u0026#34;; const long gmtOffset_sec = 28800; const int daylightOffset_sec = 0; configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); void GetTime() { struct tm timeinfo; if (!getLocalTime(\u0026amp;timeinfo)) { return; } Serial.println(\u0026amp;timeinfo, \u0026#34;%A, %Y-%m-%d %H:%M:%S\u0026#34;); }     位置获取\n由于当时并没有申请IP定位的相关API，加上之前学习爬虫时偶然在NetWork里面发现了BiliBili的相关接口：\n http://api.bilibili.com/x/web-interface/zone\n 参考链接\n API请求方式及响应参考：通过ip确定地理位置 JSON数据解析：ArduinoJson: Efficient JSON serialization for embedded C++  相关代码如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31  float lat = 0.0;\t//latitude 唯独 float lon = 0.0;\t//longitude 经度 String city = \u0026#34;\u0026#34;;\t//城市名称  void getlocation() { DynamicJsonDocument doc(1024); HTTPClient http; http.begin(\u0026#34;http://api.bilibili.com/x/web-interface/zone\u0026#34;); int httpCode = http.GET(); if (httpCode == 200) { Serial.println(\u0026#34;Get OK\u0026#34;); String resBuff = http.getString(); Serial.println(resBuff); deserializeJson(doc, resBuff); JsonObject root = doc.as\u0026lt;JsonObject\u0026gt;(); city = root[\u0026#34;data\u0026#34;][\u0026#34;city\u0026#34;].as\u0026lt;String\u0026gt;(); lat = root[\u0026#34;data\u0026#34;][\u0026#34;latitude\u0026#34;]; lon = root[\u0026#34;data\u0026#34;][\u0026#34;longitude\u0026#34;]; Serial.print(lat); Serial.print(lon); Serial.println(city); } else { Serial.println(\u0026#34;Location get error!\u0026#34;); } http.end(); // 结束当前连接 }     天气获取\nAPI来源的原因同上，选自win10上的天气资讯里抓到的API：\n https://api.msn.cn/weather/current\n 请求方式：GET\n查询字符串参数：\n   KEY VALUE 备注     latLongList: 33.13815,111.49078 经纬度   locale: zh-cn 地区   units: C    appId: 9e21380c-ff19-4c78-b4ea-19558e93a5d3    apiKey: j5i4gDqHL6nGYwx5wi5kRhXjtf2c5qgFX9fzfk0TOo    ocid: msftweather    wrapOData: FALSE     示例：\n1  curl \u0026#39;https://api.msn.cn/weather/current?latLongList=34%2C112\u0026amp;locale=zh-cn\u0026amp;units=C\u0026amp;appId=9e21380c-ff19-4c78-b4ea-19558e93a5d3\u0026amp;apiKey=j5i4gDqHL6nGYwx5wi5kRhXjtf2c5qgFX9fzfk0TOo\u0026amp;ocid=msftweather\u0026amp;wrapOData=false\u0026#39;   响应参考\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69  { \u0026#34;responses\u0026#34;: [ { \u0026#34;weather\u0026#34;: [ { \u0026#34;current\u0026#34;: { \u0026#34;baro\u0026#34;: 973, \u0026#34;cap\u0026#34;: \u0026#34;阴\u0026#34;, \u0026#34;capAbbr\u0026#34;: \u0026#34;多云\u0026#34;, \u0026#34;daytime\u0026#34;: \u0026#34;n\u0026#34;, \u0026#34;dewPt\u0026#34;: 22, \u0026#34;feels\u0026#34;: 22, \u0026#34;rh\u0026#34;: 80, \u0026#34;icon\u0026#34;: 32, \u0026#34;pvdrIcon\u0026#34;: \u0026#34;32\u0026#34;, \u0026#34;urlIcon\u0026#34;: \u0026#34;http://img-s-msn-com.akamaized.net/tenant/amp/entityid/AAehyQC.img\u0026#34;, \u0026#34;sky\u0026#34;: \u0026#34;\u0026#34;, \u0026#34;temp\u0026#34;: 25, \u0026#34;vis\u0026#34;: 6, \u0026#34;windDir\u0026#34;: 180, \u0026#34;windSpd\u0026#34;: 61, \u0026#34;created\u0026#34;: \u0026#34;2021-08-02T00:04:38+08:00\u0026#34;, \u0026#34;pvdrCap\u0026#34;: \u0026#34;多云\u0026#34;, \u0026#34;pvdrWindDir\u0026#34;: \u0026#34;南风\u0026#34;, \u0026#34;pvdrWindSpd\u0026#34;: \u0026#34;6-7级\u0026#34;, \u0026#34;aqi\u0026#34;: 34, \u0026#34;aqiSeverity\u0026#34;: \u0026#34;空气优\u0026#34;, \u0026#34;richCaps\u0026#34;: [ ], \u0026#34;alertCount\u0026#34;: 0 }, \u0026#34;provider\u0026#34;: { \u0026#34;name\u0026#34;: \u0026#34;中国天气网\u0026#34;, \u0026#34;url\u0026#34;: \u0026#34;http://www.weather.com.cn/weather/101180708.shtml\u0026#34; } } ], \u0026#34;source\u0026#34;: { \u0026#34;id\u0026#34;: \u0026#34;101180708\u0026#34;, \u0026#34;coordinates\u0026#34;: { \u0026#34;lat\u0026#34;: 33.1379738, \u0026#34;lon\u0026#34;: 111.491 }, \u0026#34;location\u0026#34;: { \u0026#34;Name\u0026#34;: \u0026#34;xichuan\u0026#34;, \u0026#34;StateCode\u0026#34;: \u0026#34;河南\u0026#34;, \u0026#34;CountryName\u0026#34;: \u0026#34;china\u0026#34;, \u0026#34;CountryCode\u0026#34;: \u0026#34;CN\u0026#34;, \u0026#34;TimezoneName\u0026#34;: \u0026#34;Asia/Shanghai\u0026#34;, \u0026#34;TimezoneOffset\u0026#34;: \u0026#34;08:00:00\u0026#34; }, \u0026#34;utcOffset\u0026#34;: \u0026#34;08:00:00\u0026#34;, \u0026#34;countryCode\u0026#34;: \u0026#34;CN\u0026#34; } } ], \u0026#34;units\u0026#34;: { \u0026#34;system\u0026#34;: \u0026#34;Metric\u0026#34;, \u0026#34;pressure\u0026#34;: \u0026#34;百帕\u0026#34;, \u0026#34;temperature\u0026#34;: \u0026#34;‎°C\u0026#34;, \u0026#34;speed\u0026#34;: \u0026#34;公里/小时\u0026#34;, \u0026#34;height\u0026#34;: \u0026#34;毫米\u0026#34;, \u0026#34;distance\u0026#34;: \u0026#34;公里\u0026#34;, \u0026#34;time\u0026#34;: \u0026#34;s\u0026#34; }, \u0026#34;copyright\u0026#34;: \u0026#34;Copyright © 2021 Microsoft and its suppliers. All rights reserved. This API cannot be accessed and the content and any results may not be used, reproduced or transmitted in any manner without express written permission from Microsoft Corporation.\u0026#34;, \u0026#34;latLongIdMap\u0026#34;: { \u0026#34;33.13815,111.49078\u0026#34;: \u0026#34;101180708\u0026#34; } }   信息解析\u0026amp;获取方式同IP地理位置查询。\n  信息显示\n这里用到了 Arduino GFX 库\n参考链接：Arduino_GFX\n  初始化：\n1 2 3 4 5 6 7 8  Arduino_DataBus *bus = new Arduino_ESP32SPI(25 /* RS */, 15 /* CS */, 14/* SCK */, 13 /* MOSI */, -1 /* MISO */, HSPI /* spi_num */); Arduino_GFX *gfx = new Arduino_ILI9225(bus, 26 /* RST */, 1); void setup(void) { Serial.begin(115200); gfx-\u0026gt;begin(); }     清除屏幕：gfx-\u0026gt;fillScreen(color);\n  输出文字：\n1 2 3 4  gfx-\u0026gt;setCursor(10, 10);\t// 设置光标位置，参考点为首个字体的左下角  gfx-\u0026gt;setFont(\u0026amp;pf_min_ys10pt8b);\t// 选择字体，若没有则使用默认字体  gfx-\u0026gt;setTextColor(RED);\t// 选择字体颜色  gfx-\u0026gt;println(\u0026#34;Hello World!\u0026#34;); // 输出到屏幕上     显示图片：\n1 2  gfx-\u0026gt;draw24bitRGBBitmap(x,y,bitmap,width,height);\t// 显示彩图 gfx-\u0026gt;drawXBitmap(x,y,gImage_code,width,height,WHITE);\t// 显示黑白二色图（二维码）     问题\n  如何显示中文？\n自定义中文字库。\n官方提供了转换的工具：Adafruit-GFX-Library/fontconvert ，按照fontconvert_win.md文档即可编译成功。\n使用方法：./fontconvert fontfile size [first] [last]\n但是，由于中文字库太过庞大，想要全部应用单靠小小的ESP32是无法承受的，因此我们需要精简，我的思路如下：\n  找出可能要显示的文字：(这里我用Python作为工具进行实现)\n1 2 3 4 5 6 7 8 9 10 11 12 13  a = \u0026#34;朗晴少云晴间多云多云阴有风平静微风和风清风强风劲风疾风大风烈风风暴狂爆风飓风热带风暴霾中度霾重度霾严重霾阵雨雷阵雨雷阵雨并伴有冰雹小雨中雨大雨暴雨大暴雨特大暴雨强阵雨强雷阵雨极端降雨毛毛雨细雨雨小雨中雨中雨大雨大雨暴雨暴雨大暴雨大暴雨特大暴雨雨雪天气雨夹雪阵雨夹雪冻雨雪阵雪小雪中雪大雪暴雪小雪中雪中雪大雪大雪暴雪浮尘扬沙沙尘暴强沙尘暴龙卷风雾浓雾强浓雾轻雾大雾特强浓雾热冷省市南阳镇江优良轻度污染东西北空气\u0026#34; # 对字符串a进行去重 a=set(a) b=\u0026#34;\u0026#34; for i in a: print(i,end=\u0026#34;\u0026#34;) b = b + i # 去重之后：少天冻雾冷!西空热云阴狂特间重降度静大爆伴多冰微浮朗扬气雪劲阵中有小染暴阳飓浓严平卷轻极夹毛雹雨省镇江雷清优北沙烈带并污龙东疾良尘强细霾晴风端和市南 # 对字符串的Unicode码进行排序 ls=[] for i in b: ls.append(ord(i)) ls.sort()     由于字体转换工具的局限性，它截取的字体必须是连续的，即按照Unicode码从[first]到[last]进行转换，然而我们需要的字的Unicode码跨度很大（从[\u0026quot; \u0026ldquo;(32)]到[\u0026ldquo;龙\u0026rdquo;(40857)]），转换后的.h文件大小高达2Mb，因此还需要再进行缩减。\n由于英文及其符号的Unicode码是连在一起的（从32到126）因此我们可以按照一定的规则将ttf文件中我们需要的字的Unicode码进行修改，在126之后进行追加我称之为字体映射[doge]，然后再在程序里写一个解析的函数即可。\n得到映射关系及部分解析代码的python程序如下：\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26  sum=0 ys={} for i in ls: if i in range(0x4e1c,ls[len(ls)-1]+1): sum+=1 print(f\u0026#34;{chr(i)}:{hex(i)}:{hex(126+sum)}\u0026#34;)\t# 映射关系 ys[chr(i)]=chr(126 + sum) print(f\u0026#39;txt.replace(\u0026#34;{chr(i)}\u0026#34;, \u0026#34;\\\\{str(hex(126+sum))[1:]}\u0026#34;);\u0026#39;)\t# 解析代码 \u0026#39;\u0026#39;\u0026#39; 输出示例: 东:0x4e1c:0x7f txt.replace(\u0026#34;东\u0026#34;, \u0026#34;\\x7f\u0026#34;); 严:0x4e25:0x80 txt.replace(\u0026#34;严\u0026#34;, \u0026#34;\\x80\u0026#34;); 中:0x4e2d:0x81 txt.replace(\u0026#34;中\u0026#34;, \u0026#34;\\x81\u0026#34;); 云:0x4e91:0x82 txt.replace(\u0026#34;云\u0026#34;, \u0026#34;\\x82\u0026#34;); .......... 飓:0x98d3:0xc6 txt.replace(\u0026#34;飓\u0026#34;, \u0026#34;\\xc6\u0026#34;); 龙:0x9f99:0xc7 txt.replace(\u0026#34;龙\u0026#34;, \u0026#34;\\xc7\u0026#34;); \u0026#39;\u0026#39;\u0026#39; # 很明显的从4w多缩减到了199   解析的函数：\n1 2 3 4 5 6 7 8 9 10 11  void printcn(String txt) { // Serial.println(txt);  txt.replace(\u0026#34;东\u0026#34;, \u0026#34;\\x7f\u0026#34;); txt.replace(\u0026#34;严\u0026#34;, \u0026#34;\\x80\u0026#34;); txt.replace(\u0026#34;中\u0026#34;, \u0026#34;\\x81\u0026#34;); txt.replace(\u0026#34;云\u0026#34;, \u0026#34;\\x82\u0026#34;); txt.replace(\u0026#34;优\u0026#34;, \u0026#34;\\x83\u0026#34;); gfx-\u0026gt;println(txt); }   得到映射关系后我们就可以对ttf文件进行修改了，利用[FontSmaller 字体文件子集化工具]将需要的文件进行简化，再用[FontLabTypeTool字体编辑器]工具对其Unicode进行修改，最后使用编译好的字体转换工具进行转换即可得到.h文件\t./fontconvert fontfile 10 32 199\n    如何得到bitmapArray？\n我用了两张图，第一张是Smart Config的二维码，因为只有黑白，所以很容易就实现了显示：\n设定参考：\n   选项 选择     输出数据类型: C语言数组(*.c)   扫描模式: 水平扫描   输出灰度: 单色   字节内象素数据反序 是    *需要修改生成的.c中的char[]类型为uint8_t[]类型\n第二张是彩色的UI背景图，使用ppt以及画图进行制作。\n然而彩色的UI背景图就不是那么容易了，无论我用这个软件怎么设置，在屏幕中显示的都只有混乱，因此只能找别的软件了。在我翻遍了github之后，找到了一个py文件（淦忘了那个py文件的具体出处链接了）运行后终于成功显示出了上下颠倒，红色变蓝色（后来百度到是因为R通道和B通道被交换了）的图片，既然py文件代码看不懂，那就主动转换源文件来 负负得正\n转换源图片为负的python代码：(拿出了还没有入门的opencv知识)\n1 2 3 4 5 6 7 8 9 10 11  import cv2 img1 = cv2.imread(\u0026#34;./IMG/bg.bmp\u0026#34;) b, g, r = cv2.split(img1) img1 = cv2.merge([r, g, b]) # 通道转换 img1 = cv2.flip(img1, 0) # 垂直翻转 cv2.imwrite(\u0026#34;out.jpeg\u0026#34;, img1)\t# 输出转换后的图片   注意：输出的图片还要另存为24色的bmp文件（利用win自带的画图的另存为）\n然后利用找到的py程序输出bitmap数组：(程序经过了我部分魔改，很抱歉我找不到程序的原作者了啊啊啊啊)\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49  import os import shutil img_out_c = list() sum = 0 def img_to_c_string(image_path, img_name): with open(image_path, \u0026#39;rb\u0026#39;) as img_file: binary_file = img_file.read() # img data img_out_c.append( \u0026#34;/*********************************************************************\\n*\\n* name: %s\\n*/\u0026#34; % (img_name)) img_out_c.append(\u0026#34;static const uint8_t %s_%s[%s] = {\u0026#34; % ( img_name[-3:], img_name[:-4].replace(\u0026#39; \u0026#39;, \u0026#39;_\u0026#39;).replace(\u0026#39;-\u0026#39;, \u0026#39;_\u0026#39;), os.path.getsize(image_path))) for x in range(int(len(binary_file) / 20)): part = binary_file[20 * x: 20 * x + 20] img_out_c.append(\u0026#34; 0x\u0026#34; + \u0026#34;, 0x\u0026#34;.join(format(x, \u0026#34;02X\u0026#34;) for x in part) + \u0026#39;,\u0026#39;) print(\u0026#34; 0x\u0026#34; + \u0026#34;, 0x\u0026#34;.join(format(x, \u0026#34;02X\u0026#34;) for x in part) + \u0026#39;,\u0026#39;) print(\u0026#34;\\n\\n\u0026#34;) if len(binary_file) % 20 != 0: part = binary_file[int(len(binary_file) / 20) * 20:len(binary_file)] img_out_c.append(\u0026#34; 0x\u0026#34; + \u0026#34;, 0x\u0026#34;.join(format(x, \u0026#34;02X\u0026#34;) for x in part)) img_out_c.append(\u0026#34;};\\n\u0026#34;) def generate_c_code(env_dir): out_path = os.path.join(env_dir, \u0026#34;img_out.h\u0026#34;) if os.path.isfile(out_path): os.remove(out_path) with open(out_path, \u0026#39;w\u0026#39;) as c_file: for bmp_line in img_out_c: c_file.write(bmp_line + \u0026#39;\\n\u0026#39;) c_file.write(\u0026#39;\\n\u0026#39;) if __name__ == \u0026#39;__main__\u0026#39;: env_dir = os.path.dirname(os.path.realpath(__file__)) bmp_dir = os.path.join(env_dir, \u0026#34;IMG\u0026#34;) if os.path.exists(bmp_dir): bmp_list = os.listdir(bmp_dir) for img_file in bmp_list: bmp_path = os.path.join(bmp_dir, img_file) print(bmp_path) img_to_c_string(bmp_path, img_file) generate_c_code(env_dir)   之后把想要的功能全部实现一波就行了！！！\n最后附上我写的虽然满是bug但总算完成了基本功能的项目源码：SwetyCore/Esp32NetworkClock: 一个基于Esp32制作的可以显示天气的时钟 (github.com) 欢迎前来Star！！\n    本项目所用API仅为学习研究所用!","date":"2021-08-01T00:00:00Z","permalink":"https://swetycore-github-io.vercel.app/p/%E7%94%A8esp32%E5%88%B6%E5%81%9A%E7%BD%91%E7%BB%9C%E6%97%B6%E9%92%9F/","title":"用ESP32制做网络时钟"},{"content":"前言 需求：根据提供的股票代码将网站 财务摘要_新浪网 的资产负债表，利润表，现金流量表三个表格保村到本地。\n过程解析 得到需求后当然是打开浏览器，然后根据传统艺能打开 DevTools 就是一顿分析，很快嗷，就得到了爬取的思路。\n 获取相关页面：对 http://vip.stock.finance.sina.com.cn/q/go.php/vInvestConsult/kind/scbhz/index.phtml?symbol={股票代码}  发送get请求，得到搜索结果。用xpath//a[@target=\u0026quot;_blank\u0026quot;] 来匹配到财务摘要的页面。 匹配相关信息：在财务摘要页面用 //*[@id=\u0026quot;toolbar\u0026quot;]/div[1]/h1/a 来获取公司名称，正则匹配 stockid/(.*?)/ctrl 来获取stockid。 获取下载链接并下载：其中，资产负债表，利润表，现金流表的下载链接分别是 http://money.finance.sina.com.cn/corp/go.php/vDOWN_BalanceSheet/displaytype/4/stockid/{stockId}/ctrl/all.phtml http://money.finance.sina.com.cn/corp/go.php/vDOWN_ProfitStatement/displaytype/4/stockid/{stockId}/ctrl/all.phtml http://money.finance.sina.com.cn/corp/go.php/vDOWN_CashFlow/displaytype/4/stockid/{stockId}/ctrl/all.phtml  遇到的问题\u0026amp;吐槽 获取页面和匹配信息都没什么难度，令人迷惑的是当我在浏览器里试图下载 excel 文件的时候，突然弹出了登录框提示登陆才能下载，当时猜测完了可能又要搞模拟登陆了（心里不由得想起了被各种加密支配的恐惧）。但当我真正登陆上去点击下载后，才发现不就一固定链接嘛还搞得那么神秘。\n项目地址：\n","date":"2021-07-01T00:00:00Z","permalink":"https://swetycore-github-io.vercel.app/p/python%E7%88%AC%E5%8F%96%E6%96%B0%E6%B5%AA%E8%B4%A2%E7%BB%8F%E7%9A%84%E9%83%A8%E5%88%86%E8%A1%A8%E6%A0%BC/","title":"Python爬取新浪财经的部分表格"},{"content":"前言 ubuntu 和 fedora 的默认中文输入法均为 ibus，但是这个输入法对与 jetbrains 家的ide均不是特别友好，经常出现输入时候卡顿严重的问题，就不得不安装其他输入法代替。\n但是 fcitx 输入法并不是开箱即用的，安装好之后还需要配置一些东西才能让它正常工作。\n步骤 1.安装 fcitx：\nsudo apt install fcitx-sunpinyin\nsudo dnf install fcitx-sunpinyin\n可选安装 fcitx-config-tool\n2.配置:\n对于 ubuntu 或者其他部分发行版需要添加环境变量。\nsudo vim /etc/profile\n在末尾加上\n1 2 3  export GTK_IM_MODULE=fcitx export QT_IM_MODULE=fcitx export XMODIFIERS=\u0026#34;@im=fcitx\u0026#34;   注销再登陆即可\n但是对于 fedora，我发现只增加环境变量就不好使了，重启之后依然无法输入中文。\n经过一番折腾后发现需要配置输入法\nalternatives --config xinputrc\n之后选择 fcitx 即可。\n","date":"2021-04-04T00:00:00Z","permalink":"https://swetycore-github-io.vercel.app/p/ubuntu%E5%92%8Cfedora%E4%B8%8B%E7%9A%84fcitx%E8%BE%93%E5%85%A5%E6%B3%95%E9%97%AE%E9%A2%98/","title":"ubuntu和fedora下的fcitx输入法问题"},{"content":"前言 众所周知，在学校里钥匙可能忘带，但是手机却不可能会不带，再加上偶然刷到了自制宿舍NFC门禁的帖子，就想整一个试一试。\n材料  Arduino UNO *1 充电宝 *1 MFRC522 （nfc模块） *1 28BYJ4 （5V步进电机） *1 ULN2003驱动板 *1  连线 \nGithub： 戳我传送\n[Warning]：出于安全性考虑，此项目仅供学习和娱乐\n","date":"2021-04-04T00:00:00Z","permalink":"https://swetycore-github-io.vercel.app/p/%E5%9F%BA%E4%BA%8Earduino%E5%88%B6%E4%BD%9C%E7%9A%84%E5%AE%BF%E8%88%8Dnfc%E9%97%A8%E7%A6%81/","title":"基于Arduino制作的宿舍NFC门禁"},{"content":"前言： 在开发自动健康打卡的过程中，因为 post 不止提交有当日体温，还带有最近动态等个人信息，最初是用 json 文件来存储信息，但是这样每次信息更新都要重新手动更新 json 文件很不方便，而且只能自己一个人用。\n用法： 这里贴上一个我当时看的教程连接：\u0026gt;点我传送\u0026lt; 需要提取的信息大致分为以下这几类\n1.input/number类型：\u0026lt;input id=\u0026quot;ykt\u0026quot; class=\u0026quot;weui_input\u0026quot; type=\u0026quot;text\u0026quot; name=\u0026quot;ykt\u0026quot; placeholder=\u0026quot;请输入学号\u0026quot; value=\u0026quot;1234567890\u0026quot; readonly=\u0026quot;readonly\u0026quot;\u0026gt; \u0026lt;/div\u0026gt;\n\u0026lt;input class=\u0026quot;weui_input\u0026quot; type=\u0026quot;number\u0026quot; id=\u0026quot;nl\u0026quot; name=\u0026quot;nl\u0026quot; placeholder=\u0026quot;请输入年龄\u0026quot; maxlength=\u0026quot;3\u0026quot; required=\u0026quot;\u0026quot; value=\u0026quot;18\u0026quot;\u0026gt;\n2.radio类型： \u0026lt;input class=\u0026quot;weui-check\u0026quot; name=\u0026quot;xb\u0026quot; type=\u0026quot;radio\u0026quot; disabled=\u0026quot;disabled\u0026quot; value=\u0026quot;女\u0026quot;\u0026gt;\u0026amp;nbsp;女Female\u0026lt;/div\u0026gt;\n3.select_type：\u0026lt;select id=\u0026quot;qtyc\u0026quot; class=\u0026quot;select_type\u0026quot; name=\u0026quot;qtyc\u0026quot;\u0026gt;\u0026lt;option value=\u0026quot;\u0026quot; selected=\u0026quot;selected\u0026quot;\u0026gt;\u0026lt;/option\u0026gt;\u0026lt;option value=\u0026quot;无\u0026quot;\u0026gt;无 None\u0026lt;/option\u0026gt;\u0026lt;option value=\u0026quot;不发烧但咳嗽\u0026quot;\u0026gt;不发烧但咳嗽 No fever but cough\u0026lt;/option\u0026gt;\u0026lt;option value=\u0026quot;不发烧但腹泻\u0026quot;\u0026gt;不发烧但腹泻 No fever but diarrhea\u0026lt;/option\u0026gt;\u0026lt;/select\u0026gt; 解决方案\n1.导入 lxml\nfrom lxml import etree\n2.利用 etree.HTML，将字符串解析为 HTML 文档 html = etree.HTML(text)\n3.xpath 匹配 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17  result=html.xpath(\u0026#39;//input[@type=\u0026#34;text\u0026#34;]\u0026#39;) html.xpath(\u0026#39;//input[@type=\u0026#34;number\u0026#34;]\u0026#39;) html.xpath(\u0026#39;//input[@type=\u0026#34;radio\u0026#34; and @checked=\u0026#34;checked\u0026#34;]\u0026#39;) # 多个属性匹配（类型是radio并且被选中） # 上面几个返回的是所有匹配到的结果【list】可以用for遍历。 for i in result: key = i.xpath(\u0026#39;./@name\u0026#39;)[0] value = i.xpath(\u0026#39;./@value\u0026#39;)[0] 这样就获取到了表单所需要的key和对应的value。 下面是select_type的： selects = html.xpath(\u0026#39;//select[@class=\u0026#34;select_type\u0026#34;]\u0026#39;) for select in selects: option = select.xpath(\u0026#39;./option[@selected=\u0026#34;true\u0026#34;]\u0026#39;)[0] key = option.xpath(\u0026#39;../@name\u0026#39;)[0] value = option.xpath(\u0026#39;./@value\u0026#39;)[0]     至此，自动提取已经填过的表单项目的任务已经完成。\n","date":"2021-03-26T00:00:00Z","permalink":"https://swetycore-github-io.vercel.app/p/python-lxml-%E5%BA%93%E7%9A%84%E4%BD%BF%E7%94%A8/","title":"Python lxml 库的使用"},{"content":"前言 在我刚开始创建这个博客的时候，每次发文章都需要将整个项目pull下来再push上去，十分不方便，于是就想做一个能够不用git就实现的快速文章上传工具，去网络上一搜，果然有个github3的模块可以实现。\n过程   导入模块：\nimport github3\n  实现登陆：\n1 2 3 4 5 6 7 8 9  def connect_to_github(): try: gh=login(token=input(\u0026#34;Input your token:\u0026#34;)) repo=gh.repository(\u0026#34;SwetyCore\u0026#34;,\u0026#34;swetycore.github.io\u0026#34;) branch=repo.branch(\u0026#34;main\u0026#34;) return gh, repo, branch except Exception as msg: print(f\u0026#39;Token error!!!\\n{msg}\\nPlease retry.\u0026#39;) connect_to_github()   ``\n  上传文章：\n1 2 3 4 5 6  def store_data(data,filename): gh, repo, branch = connect_to_github() remote_path = f\u0026#34;_posts/{filename}\u0026#34; repo.create_file(remote_path, \u0026#34;Commite message\u0026#34;, data) print(\u0026#34;upload success\u0026#34;) return   ``\n  吐槽  为什么网上的相关教程这么少哇 网上的教程中的tree = branch.commit.commit.tree.recurse()已经不再适用。 所以判断文件是否存在应该改为 1 2 3 4 5 6 7 8  def is_file_exists(filepath): gh, repo, branch = connect_to_github() tree = branch.commit.commit.tree.to_tree().recurse() for filename in tree.tree: if filepath in filename.path: return True else: return False       上传文件不能重名！！！！(以后再想办法解决吧【恼】)  ","date":"2021-03-26T00:00:00Z","permalink":"https://swetycore-github-io.vercel.app/p/python%E5%AE%9E%E7%8E%B0%E5%8D%9A%E5%AE%A2%E6%96%87%E7%AB%A0%E7%9A%84%E4%B8%8A%E4%BC%A0/","title":"Python实现博客文章的上传"},{"content":"前言： 这个东西其实在寒假期间就写好了，但是每天都需要手动的健康打卡，但是自己又是非常的懒，一不小心睡过头或者玩过头了就把这件事忘的一干二净，当时虽然已经学了一点爬虫的方法，但是也只会爬点文字，图片一类的东西，对于需要登陆才能获取到信息的网站没有一点办法。自动打卡首先需要登陆综合门户，那就硬着头皮面向百度编程吧[无奈]\n过程解析:  初次请求登录门户(get):   https://pass.ujs.edu.cn/cas/login\n 请求验证码(get):   https://pass.ujs.edu.cn/cas/captcha.html\n 再次用请求登录门户 (post) ,并提交登录表单.  三次请求如果都成功并且无错误,应该返回成功登陆后的界面.\npost表单内容解析： 1 2 3 4 5 6 7 8  username: 1234567890 password: gfgwDALwERl0MuTBfg+U/m81JBDbksfasfTj8msH9HqqKztL+3lIhePVsFD5GXoDi7DYyQs7YoeN1Yz0RlMhegECvXfiIsQ= captchaResponse: aphc lt: LT-958050-a0kzJW9kweaskdgfHJdaY1Ug7oHe2eQ1611227557350-OC02-cas dllt: userNamePasswordLogin execution: e2s1 _eventId: submit rmShown: 1    username: 学号 password: 加密后的密码 captchaResponse: 验证码 lt: 一串奇怪的字符,在第一次请求的 response 里面,可以用正则表达式 \u0026lt;input name=\u0026quot;lt\u0026quot; type=\u0026quot;hidden\u0026quot; value=\u0026quot;(.*?)\u0026quot;/\u0026gt; 匹配到. dllt: 固定值 execution: 奇怪的字符,使用正则表达式 \u0026lt;input name=\u0026quot;execution\u0026quot; type=\u0026quot;hidden\u0026quot; value=\u0026quot;(.*?)\u0026quot;/\u0026gt; 匹配 _eventId: 固定值 rmShown: 固定值  密码加密解析: 只是将网页的js代码稍作整理提取,有兴趣的大佬可以研究一下具体的加密过程(其实是我不会). 其中的加密函数 _etd2() 需要 两个参数:\n 密码 pwdDefaultEncryptSalt  其中pwdDefaultEncryptSalt可以用正则表达式 var pwdDefaultEncryptSalt = \u0026quot;(.*?)\u0026quot;; 匹配.\n我已经将加密的代码整理为两个js文件,使用时候只需要运行jiami.js里面的 _etd2() 函数并且传入相应的参数,获取函数返回值即可.\n注意事项  三次请求应该是同一个 session 完成  请求示例: 详见login.py\n重写了 login.py ,建议使用 loginRe.py\n 调用登陆模块示例:  1 2 3 4 5 6 7 8  import loginRe import getpass if __name__ == \u0026#39;__main__\u0026#39;: username = input(\u0026#39;学号: \u0026#39;) pwd = getpass.getpass(\u0026#34;密码: \u0026#34;) lg = loginRe.Login(\u0026#39;6e9b090sdad5c1234d0bbb88de18097eb\u0026#39;) lg.Login(username=username, password=pwd)   tip: 阿里云 ocr 识别请自行申请接口 key. 戳我传送\n模拟登陆的用途:应该没什么用吧 (bushi)\n仅供学习交流,请不要用于其他方面!!!!\n希望不至于被叫去喝茶 (逃)\n总结： 虽然这个项目的难度并不高，但是我对于需要登陆的爬虫的第一次尝试。 我竟然笨到研究了三天才整完。 项目详见 Jiangda-Portal-Automatic-Login。\n","date":"2021-03-25T00:00:00Z","permalink":"https://swetycore-github-io.vercel.app/p/python-%E6%A8%A1%E6%8B%9F%E7%99%BB%E9%99%86/","title":"Python 模拟登陆"}]