Bootstrap

小白尝试51单片机数字识别

起因:b站刷到一个在点阵屏上用按键画数字然后识别的视频,有点意思想自己做做

目标

1、51引脚不够,用红外来控制单片机,在点阵屏上画数字

2、画完后,红外控制开始识别

3、识别完成在LCD屏上显示

代码参考了江协科技和普中手册

0、public

//public.h
#ifndef _PUBLIC_H_
#define _PUBLIC_H_
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long

#include "reg52.h"
// LED点阵 从左往右每一列的数据
extern u8 GLED_PER_COL_DATA[8];
// 坐标 前四位x 后四位y
extern u8 point;

// 控制

#define DISABLE 0
#define ENABLE 1

void delay_10us(u16 ten_us);
void delay_ms(u16 ms);
float my_exp(float x);
#endif
//public.c
#include "public.h"

/*******************************************************************************
 * 函 数 名       : delay_10us
 * 函数功能		 : 延时函数,ten_us=1时,大约延时10us
 * 输    入       : ten_us
 * 输    出    	 : 无
 *******************************************************************************/
void delay_10us(u16 ten_us) {
    while (ten_us--);
}

/*******************************************************************************
 * 函 数 名       : delay_ms
 * 函数功能		 : ms延时函数,ms=1时,大约延时1ms
 * 输    入       : ms:ms延时时间
 * 输    出    	 : 无
 *******************************************************************************/
void delay_ms(u16 ms) {
    u16 i, j;
    for (i = ms; i > 0; i--)
        for (j = 110; j > 0; j--);
}

// 求e的x次幂 
float my_exp(float x) {
    x = 1.0f + x / 1024;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    return x;
}

1、串口

首先肯定是串口代码,用于调试

//uart.h
#ifndef _UART_H_
#define _UART_H_

#include <stdio.h>

#include "public.h"

#define UART_REC_LEN 32  // 定义最大接收字节数 50

extern u8 xdata UART_RX_BUF[UART_REC_LEN];  // 接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 xdata UART_RX_STA;               // 接收状态标记

/* printf */
char putchar(char c);
void UART_Init(void);
void UART_SendData(u8 dat);
void UART_SendString_DisIR(u8 *pbuf);
void UART_SendString_EnIr(u8 *pbuf);

// 串口接收使用
/* if (UART_RX_STA & 0x8000){  // 判断串口是否接收完数据,接收到的数据就是UART_RX_BUF
    UART_RX_STA = 0;  // 清除标记,等待下次接收
    UART_SendString(UART_RX_BUF);
    UART_SendString("\r\n");
} */

#endif

/*
%c:字符。
%d:十进制整数。
%i:整数,基本等同于%d。
%o:八进制整数。
%p:指针。
%s:字符串。
%u:符(unsigned int)。
%x:十六进制整数。
%%:输出一个百分号。
%zd: size_t类型。

%a:十六进制浮点数,字母输出为小写。
%A:十六进制浮点数,字母输出为大写。
%e:使用科学计数法的浮点数,指数部分的e为小写。
%E:使用科学计数法的浮点数,指数部分的E为大写。
%f:小数(包含 float 类型和 double类型) 。
%g:6个有效数字的浮点数。整数部分一旦超过6位,就会自动转为科学计数法,指数部分的e为小写。
%G:等同于%g,唯一的区别是指数部分的E为大写。
%Le:科学计数法表示的long double类型浮点。
%Lf: long double类型浮点。

%hd:十进制 short int型。
%ho:八进制 short int型。
%hx:十六进制 short int类型。
%hu: unsigned short int型。

%ld:十进制 long int类型。
%lo:八进制 long int类型。
%lx:十六进制 long int类型。
%lu: unsigned long int。

%lld:十进制 long long int类型。
%llo:八进制 long long int类型。
%llx:十六进制 long long int型。
%llu: unsigned long long int型。

%n:已输出的字符串数量。该占位符本身不输出,只将值存储在指定变量之中。
 */
//uart.c
#include "uart.h"

#define RELOAD_COUNT 0xFA  // 宏定义波特率发生器的载入值 [email protected]

// 串口初始化
void UART_Init(void)  // [email protected]
{
    PCON |= 0x80;        // 波特率倍速
    SCON = 0x50;         // 8位数据,可变波特率
    TMOD &= 0x0F;        // 清除定时器1模式位
    TMOD |= 0x20;        // 设定定时器1为8位自动重装方式
    TL1 = RELOAD_COUNT;  // 设定定时初值
    TH1 = TL1;           // 设定定时器重装值
    ET1 = 0;             // 禁止定时器1中断
    TR1 = 1;             // 启动定时器1
    // 开启中断
    EA = 1;  // 总中断控制
    ES = 1;  // 串口中断
}

// 串口发送一个字节
void UART_SendData(u8 dat) {
    ES = 0;           // 关闭串口中断
    TI = 0;           // 清发送完毕中断请求标志位
    SBUF = dat;       // 发送
    while (TI == 0);  // 等待发送完毕
    TI = 0;           // 清发送完毕中断请求标志位
    ES = 1;           // 允许串口中断
}

// 重写 putchar 函数, 然后就可直接用printf打印
char putchar(char c) {
    UART_SendData(c);
    return c;
}

// 串口发送字符串 保证字符串发送完整
void UART_SendString_DisIR(u8 *pbuf) {
    ES = 0;                // 关闭串口中断
    TI = 0;                // 清发送完毕中断请求标志位
    while (*pbuf != '\0')  // 遇到空格跳出循环
    {
        // UART_SendData(*pbuf);
        SBUF = *pbuf;     // 发送
        while (TI == 0);  // 等待发送完毕
        TI = 0;           // 清发送完毕中断请求标志位
        delay_10us(5);
        pbuf++;
    }
    ES = 1;  // 允许串口中断
}

// 串口发送字符串,期间可被其它发送中断打断
void UART_SendString_EnIr(u8 *pbuf) {
    while (*pbuf != '\0')  // 遇到空格跳出循环
    {
        UART_SendData(*pbuf);
        delay_10us(5);
        pbuf++;
    }
}

u8 xdata UART_RX_BUF[UART_REC_LEN];  // 接收缓冲,最大UART_REC_LEN个字节.带末尾结束符
/*  接收状态标记
 bit15,	接收完成标志
 bit14,	接收到0x0d,回车键标志,\r
 bit13~0,	接收到的有效字节数目 */
u16 xdata UART_RX_STA = 0;

// 串口接收中断函数
void UART_IRQn() interrupt 4 {
    u8 r;

    if (RI) {
        RI = 0;                           // 清除接收中断标志位
        r = SBUF;                         // 读取接收到的数据
        if ((UART_RX_STA & 0x8000) == 0)  // 接收还未完成
        {
            if (UART_RX_STA & 0x4000)  // 接收到了0x0d \r
            {
                if (r != 0x0a) {      // 换行符,接收错误\n
                    UART_RX_STA = 0;  // 接收错误,重新开始
                } else {
                    UART_RX_STA |= 0x8000;                     // 接收完成了
                    UART_RX_BUF[UART_RX_STA & 0X3FFF] = '\0';  // 添加结束符
                }
            } else  // 还没收到0X0D
            {
                if (r == 0x0d) {
                    UART_RX_STA |= 0x4000;
                } else {
                    UART_RX_BUF[UART_RX_STA & 0X3FFF] = r;
                    UART_RX_STA++;
                    if (UART_RX_STA > (UART_REC_LEN - 2))
                        UART_RX_STA = 0;  // 接收数据错误,重新开始接收
                }
            }
        }
    }
}

 2、8*8矩阵led

//leds.h
#ifndef _LEDS_H_
#define _LEDS_H_

#include "public.h"
// 使用P0 P34 P35 P36
#define LEDDZ_COL_PORT P0  // 点阵列控制端口
// 定义 74HC595 控制管脚
sbit SRCLK = P3 ^ 6;  // 移位寄存器时钟输入
sbit MRCLK = P3 ^ 5;  // 存储寄存器时钟输入
sbit SER = P3 ^ 4;    // 串行数据输入

void hc595_write_data(u8 dat);
void led_display();

#endif
//uart.c
#include "leds.h"

/********************************************************************
***********
* 函 数 名 : hc595_write_data(u8 dat)
* 函数功能 : 向 74HC595 写入一个字节的数据
* 输 入 : dat:数据
* 输 出 : 无
*********************************************************************
**********/
void hc595_write_data(u8 dat) {
    u8 i = 0;
    for (i = 0; i < 8; i++)  // 循环 8 次即可将一个字节写入寄存器中
    {
        SER = dat >> 7;  // 优先传输一个字节中的高位
        dat <<= 1;       // 将低位移动到高位
        SRCLK = 0;
        delay_10us(1);
        SRCLK = 1;
        delay_10us(1);  // 移位寄存器时钟上升沿将端口数据送入寄存器中
    }
    MRCLK = 0;
    delay_10us(1);
    MRCLK = 1;  // 存储寄存器时钟上升沿将前面写入到寄存器的数据输出
}

/********************************************************************
 * 函 数 名 : led_display()
 * 函数功能 : 在点阵上显示数据
 * 输 入 : GLED_PER_COL_DATA 从左往右每一列的位选数据
 * 输 出 : 无
 * 备 注 : 无
 * *********************************************************************
 */
void led_display() {
    u8 i = 0;
    for (; i < 8; i++)  // 循环 8 次扫描
    {
        u8 tmp = (i == (point >> 4)) ? (GLED_PER_COL_DATA[i] | (0x80 >> (point & 0x0f))) : GLED_PER_COL_DATA[i];  // 获取当前列的数据
        LEDDZ_COL_PORT = ~(0x80 >> i);                                                                            // 传送列选数据
        hc595_write_data(tmp);                                                                                    // 传送位选数据
        delay_ms(1);                                                                                              // 延时一段时间,等待显示稳定
        hc595_write_data(0x00);                                                                                   // 消影
    }
}

3、红外

要用到定时器0

//timer.h
#ifndef _TIMER_H_
#define _TIMER_H_
#include "public.h"

void timer0_init();
void timer0_set_counter(u16 value);
u16 timer0_get_counter(void);
void timer0_cmd(u8 ensta);
/* // 定时器 0 中断1函数模板
void timer0_routine() interrupt 1 {
    static u16 count = 0;
    count++;
    if (count == 1000) {
    }
} */

#endif
//timer.c
#include "timer.h"

/****************************************************************
***************
* 函 数 名 : Timer0Init
* 函数功能 : 定时器 0 初始化,不使用中断
* 输 入 : 无
* 输 出 : 无
*****************************************************************
**************/
void timer0_init() {
    TMOD &= 0XF0;  // 清除定时器 0 模式位
    TMOD |= 0X01;  // 选择为定时器 0 模式,工作方式 1,仅用 TR0 打开启动。

    TF0 = 0;  // 清除 TF0 标志
    TR0 = 0;  // 定时器 0 停止

    TH0 = 0xFC;  // 给定时器赋初值
    TL0 = 0x18;

    // ET0 = 1;  // 打开定时器 0 中断允许
    // EA = 1;   // 打开总中断
    // PT0 = 1;  // 设置定时器 0 为高优先级
}

/****************************************************************
 * 函 数 名 : void timer0_set_counter(u16 value)
 * 函数功能 : 设置定时器 0 计数值
 * 输 入 : value 定时器 0 计数值
 * 输 出 : 无
 * ***************************************************************
 */
void timer0_set_counter(u16 value) {
    TH0 = value >> 8;
    TL0 = value;
}

/****************************************************************
 * 函 数 名 : u16 timer0_get_counter(void)
 * 函数功能 : 获取定时器 0 计数值
 * 输 入 : 无
 * 输 出 : 定时器 0 计数值
 * ***************************************************************
 */
u16 timer0_get_counter(void) {
    return (TH0 << 8) | TL0;
}

/****************************************************************
 * 函 数 名 : void timer0_cmd(FunctionalState ensta)
 * 函数功能 : 定时器 0 启动/停止
 * 输 入 : ensta 定时器 0 启动ENABLE/停止DISABLE
 * 输 出 : 无
 * ***************************************************************
 */
void timer0_cmd(u8 ensta) {
    TR0 = ensta;
}

 用到中断0

//interrupt.h
#ifndef _INTERRUPT_H_
#define _INTERRUPT_H_

#include "public.h"

void int0_init(void);
/* // 外部中断0中断函数模板
void int0_routine(void) interrupt 0 {
} */
#endif
//interrupt.c
#include "interrupt.h"
/**
 * @brief  外部中断0初始化
 * @param  无
 * @retval 无
 */
void int0_init(void) {
    IT0 = 1;  // 下降沿触发
    IE0 = 0;  // 清除外部中断0标志
    EX0 = 1;  // 打开外部中断0
    EA = 1;   // 打开总中断
    PX0 = 1;  // 设置外部中断0为高优先级
}

红外 

//ir.h
#ifndef _IR_H_
#define _IR_H_

#include "cnn.h"
#include "interrupt.h"
#include "public.h"
#include "timer.h"

/**
 * 红外编码
 * start-> 0: 900 * 10us 1: 450 *10us
 * data:
 *     0-> 0: 56 * 10us 1: 56 * 10us
 *     1-> 0: 56 * 10us 1: 169 * 10us
 * repeat-> 0: 900 * 10us 1: 225 * 10us
 * 长度: 110ms
 */

void ir_init(void);
void cmd_exec(void);

#endif
//ir.c
#include "ir.h"

u16 ir_time;
u8 ir_state;

const u32 code C = 1;
u32 xdata ir_data;  // 格式:地址+地址反码+命令+命令反码 8+8+8+8
u8 ir_data_index;

u8 ir_address;
u8 ir_command;

// 红外接收器初始化
void ir_init(void) {
    timer0_init();
    int0_init();
}

/* 普中自带遥控器 不好用
ir_data: ffffa25d 电源
ir_data: 0000629d Mode
ir_data: ffffe21d 静音
ir_data: 000022dd 启停
ir_data: 000002fd 左
ir_data: ffffc23d 右
ir_data: ffffe01f EQ e0
ir_data: ffffa857 VOL-
ir_data: ffff906f VOL+
ir_data: 00006897 0
ir_data: ffff9867 RPT
ir_data: ffffb04f U/SD
ir_data: 000030cf 1
ir_data: 000018e7 2 18
ir_data: 00007a85 3
ir_data: 000010ef 4 10
ir_data: 000038c7 5 38
ir_data: 00005aa5 6 5a
ir_data: 000042bd 7
ir_data: 00004ab5 8 4a
ir_data: 000052ad 9
 */
/* switch (ir_command) {
case 0x18: {  // 2 y-
    if ((point & 0x0f) == 0)
        point |= 0x07;
    else
        point--;
    break;
}
case 0x4a: {  // 8 y+
    if ((point & 0x0f) == 7)
        point &= 0xf0;
    else
        point++;
    break;
}
case 0x10: {  // 4 x-
    if ((point & 0xf0) == 0)
        point |= 0x70;
    else
        point -= 0x10;
    break;
}
case 0x5a: {  // 6 x+
    if ((point & 0xf0) == 0x70)
        point &= 0x0f;
    else
        point += 0x10;
    break;
}
case 0x38: {  // 5 反转
    GLED_PER_COL_DATA[point >> 4] ^= (0x80 >> (point & 0x0f));
    break;
}
case 0xe0: {  // 开始
    break;
}
} */

/*
小米万能遥控器 3MDVD播放机
ir_data: ffff 80 7f 上
ir_data: ffff 90 6f 下
ir_data: ffff 98 67 左
ir_data: ffff 88 77 右
ir_data: 0000 02 fd OK
ir_data: ffff e8 17 开始
              e0 清除
 */

// 命令执行
void cmd_exec(void) {
    switch (ir_command) {
    case 0x80: {  // 上 y-
        if ((point & 0x0f) == 0)
            point |= 0x07;
        else
            point--;
        break;
    }
    case 0x90: {  // 下 y+
        if ((point & 0x0f) == 7)
            point &= 0xf0;
        else
            point++;
        break;
    }
    case 0x98: {  // 左 x-
        if ((point & 0xf0) == 0)
            point |= 0x70;
        else
            point -= 0x10;
        break;
    }
    case 0x88: {  // 右 x+
        if ((point & 0xf0) == 0x70)
            point &= 0x0f;
        else
            point += 0x10;
        break;
    }
    case 0x02: {  // ok 反转
        GLED_PER_COL_DATA[point >> 4] ^= (0x80 >> (point & 0x0f));
        break;
    }
    case 0xe0: {  // 清除
        u8 i = 0;
        for (; i < 8; i++) {
            GLED_PER_COL_DATA[i] = 0;
        }
        break;
    }
    case 0xe8: {  // 开始
        get_res();
        break;
    }
    }
}

// 外部中断0中断函数模板
void int0_routine(void) interrupt 0 {
    if (ir_state == 0) {        // 空闲状态
        timer0_set_counter(0);  // 下降沿触发,进入中断,开始计时解码
        timer0_cmd(ENABLE);
        ir_state = 1;

    } else if (ir_state == 1) {          // 等待Start信号或Repeat信号
        ir_time = timer0_get_counter();  // 下一个下降沿到达,计算时间
        timer0_set_counter(0);           // 计时器清零

        if (ir_time > 12442 - 1000 && ir_time < 12442 + 1000) {
            ir_state = 2;  // 接收到了Start信号 9ms+450ms; 之后进行数据接收
        } /*  else if (ir_time > 10368 - 1000 && ir_time < 10368 + 1000) {
             // 接收到了Repeat信号 9ms+2.25ms; 之后结束
             timer0_cmd(DISABLE);
             ir_state = 0;
             // cmd_exec();
         } */
        else {
            ir_state = 1;  // 接收出错,两下降沿时间差不对;重新接收,等待下一个下降沿时间差
        }

    } else if (ir_state == 2) {
        ir_time = timer0_get_counter();
        timer0_set_counter(0);

        if (ir_time > 1032 - 1000 && ir_time < 1032 + 500) {  // 接收到数据0
            ir_data &= ~(0x0001 << (31 - ir_data_index));
            ir_data_index++;
        } else if (ir_time > 2074 - 500 && ir_time < 2074 + 1000) {  // 接收到数据1
            ir_data |= 0x0001 << (31 - ir_data_index);
            ir_data_index++;
        } else {  // 接收出错,两下降沿时间差不对;重新接收,等待下一个satrt/repeat信号
            ir_data_index = 0;
            ir_state = 1;
        }

        if (ir_data_index >= 32) {  // 接收到了32位数据 8+8+8+8
            ir_data_index = 0;
            /* ir_address = (u8)(ir_data >> 24);//省略 */
            ir_command = (u8)(ir_data >> 8);
            timer0_cmd(DISABLE);
            ir_state = 0;

            // 数据验证 普中的红外遥控器 地址与反码相同,命令与反码按位取反
            if (/* (ir_address == (u8)(ir_data >> 16)) &&//省略 */ (ir_command == ~(u8)(ir_data))) {
                cmd_exec();
            }
        }
    }
}

4、LCD

lcd原来的8位数据口接在P0上,但P0被矩阵led用了,所以用杜邦线接到P1上,换一下LCD_DataPort 

//lcd1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
#include "public.h"
#include "reg52.h"
// 引脚配置:
sbit LCD_RS = P2 ^ 6;
sbit LCD_RW = P2 ^ 5;
sbit LCD_EN = P2 ^ 7;
#define LCD_DataPort P1
// 用户调用函数:
void LCD_Init();                                        //
void LCD_ShowString(u8 Line, u8 Column, char *String);  //

#endif
//lcd1602.c
#include "lcd1602.h"

/**
 * @brief  LCD1602写命令
 * @param  Command 要写入的命令
 * @retval 无
 */
void LCD_WriteCommand(u8 Command) {
    LCD_RS = 0;
    LCD_RW = 0;
    LCD_DataPort = Command;
    LCD_EN = 1;
    delay_ms(1);
    LCD_EN = 0;
    delay_ms(1);
}

/**
 * @brief  LCD1602写数据
 * @param  Data 要写入的数据
 * @retval 无
 */
void LCD_WriteData(u8 Data) {
    LCD_RS = 1;
    LCD_RW = 0;
    LCD_DataPort = Data;
    LCD_EN = 1;
    delay_ms(1);
    LCD_EN = 0;
    delay_ms(1);
}

/**
 * @brief  LCD1602设置光标位置
 * @param  Line 行位置,范围:1~2
 * @param  Column 列位置,范围:1~16
 * @retval 无
 */
void LCD_SetCursor(u8 Line, u8 Column) {
    if (Line == 1) {
        LCD_WriteCommand(0x80 | (Column - 1));
    } else if (Line == 2) {
        LCD_WriteCommand(0x80 | (Column - 1 + 0x40));
    }
}

/**
 * @brief  LCD1602初始化函数
 * @param  无
 * @retval 无
 */
void LCD_Init() {
    LCD_WriteCommand(0x38);  // 八位数据接口,两行显示,5*7点阵
    LCD_WriteCommand(0x0c);  // 显示开,光标关,闪烁关
    LCD_WriteCommand(0x06);  // 数据读写操作后,光标自动加一,画面不动
    LCD_WriteCommand(0x01);  // 光标复位,清屏
}

/**
 * @brief  在LCD1602指定位置开始显示所给字符串
 * @param  Line 起始行位置,范围:1~2
 * @param  Column 起始列位置,范围:1~16
 * @param  String 要显示的字符串
 * @retval 无
 */
void LCD_ShowString(u8 Line, u8 Column, char *String) {
    u8 i;
    LCD_SetCursor(Line, Column);
    for (i = 0; String[i] != '\0'; i++) {
        LCD_WriteData(String[i]);
    }
}

5、识别

可以在电脑上训练,但要在51上识别,不能用库

不会,去找了个能懂的视频:10分钟!60行代码!从零实现数字识别【不调用任何深度学习库】 可行

5.1 获取数据集

没有8*8点阵的数据集,为了方便用uni-app写了个网页,花了十几分钟手搓了500个

<template>
	<view style="display: flex;flex-direction:row" class="content">
		<view style="width: 620px;margin-right: 20px;margin-left: 40px;">
			<scroll-view style="border: 2px solid #ccc;height: 400px;" scroll-y>
				<text selectable>{{content}}</text>
			</scroll-view>
			<view style="display: flex;flex-direction: row;margin: 10px;">
				<button @click="dialog">清除</button>
				<button @click="storage">存储</button>
				<text>数量: {{cnt}}</text>
			</view>
		</view>
		<view class="content">
			<view class="content">
				<view v-for="i in [0,1,2,3,4,5,6,7]" :id="i">
					<button style="width: 40px;height: 40px;text-align: center;border: 0px;" :type="primarys[i][j]"
						v-for="j in [0,1,2,3,4,5,6,7]" :id="`${i}${j}`">{{nums[i][j]}}</button>
				</view>
			</view>
			<view class="content" style="flex-direction: column;margin: 10px;">
				<input type="button" @input="input" style="width: 40px;border: 2px solid #ccc;margin: 10px;" />
				<button style="margin: 5px;" @click="save">暂存</button>
				<button @click="clear">清除</button>
			</view>
		</view>
	</view>

	<!-- 加确认框,搓了一大堆,点错了就很淦 -->
	<uni-popup ref="popup" type="dialog">
		<uni-popup-dialog mode='base' type='warn' :duration="2000" :before-close="true" @close="popup.close()"
			@confirm="clearContent"></uni-popup-dialog>
	</uni-popup>
</template>

<script setup lang="ts">
	import { ref } from 'vue';
	import { onLoad, onReady } from '@dcloudio/uni-app'
	const nums = ref<number[][]>([])
	const primarys = ref<string[][]>([])
	const digit = ref('0')
	const cnt = ref(0)
	const content = ref('')
	const popup = ref<any>(null)

	//输入当前的字符画的值
	const input = (event) => {
		digit.value = event.detail.value
	}

	//保存到文件的函数 https://blog.csdn.net/dangfulin/article/details/141495821
	function saveToFile(content, filename) {
		const blob = new Blob([content], { type: 'text/plain' });
		const url = URL.createObjectURL(blob);

		const link = document.createElement('a');
		link.href = url;
		link.download = filename;

		// 这行是必要的,用于在浏览器中触发下载
		document.body.appendChild(link);

		link.click();

		// 清理并移除链接
		document.body.removeChild(link);
		URL.revokeObjectURL(url);
	}

	//保存 按列衔接存为一行
	const storage = () => {
		console.log('存', content.value);
		saveToFile(content.value, `${digit.value}.txt`)
		clearContent()
	}

	const dialog = () => {
		popup.value.open()
	}

	//清除已暂存的字符画
	const clearContent = () => {
		content.value = ''
		cnt.value = 0
		popup.value.close()
	}

	//鼠标按下和抬起事件 用于左键按下时画数字字形
	let flag = false
	addEventListener('mousedown', () => { flag = true })
	addEventListener('mouseup', () => {
		flag = false
	})

	let hasEnter : boolean[][] = []  //再次滑入时,不反转
	let eles : HTMLElement[][] = []
	onReady(() => {
		//获取8*8每个按钮 添加鼠标滑入事件 画字型
		for (let row = 0; row < 8; row++) {
			eles.push([])
			for (let col = 0; col < 8; col++) {
				eles[row][col] = document.getElementById(`${row}${col}`)
				eles[row][col].addEventListener('mouseenter', () => {
					if (flag && !hasEnter[row][col]) {
						change(row, col)
						hasEnter[row][col] = true
					}
				})
				eles[row][col].addEventListener('mousedown', () => {
					//添加滑动事件起始点的按下事件 从起点开始
					change(row, col)
					hasEnter[row][col] = true
				})
			}
		}
	})

	// 反转
	const change = (row : string | number, col : string | number) => {
		nums.value[row][col] = nums.value[row][col] ? 0 : 1
		primarys.value[row][col] = nums.value[row][col] ? 'warn' : 'primary'
	}

	//暂存 这里行列反转了??? 不知道为什么 不过刚好要按列存取
	const save = async () => {
		let str = ''
		str = `${digit.value}\n`
		for (let row = 0; row < 8; row++) {
			for (let col = 0; col < 8; col++) {
				str += `${nums.value[row][col]}`
			}
		}
		str += '\n'
		content.value += str
		cnt.value++
		clear()
	}

	//清除数字字形
	const clear = () => {
		for (let row = 0; row < 8; row++) {
			for (let col = 0; col < 8; col++) {
				hasEnter[row][col] = false
				nums.value[row][col] = 0;
				primarys.value[row][col] = 'primary'
			}
		}
	}

	//初始化
	onLoad(() => {
		for (let row = 0; row < 8; row++) {
			hasEnter.push([])
			nums.value.push([]);
			primarys.value.push([])
			for (let col = 0; col < 8; col++) {
				hasEnter[row][col] = false
				nums.value[row][col] = 0;
				primarys.value[row][col] = 'primary'
			}
		}
	})
</script>

<style>
	.content {
		display: flex;
		align-items: center;
		justify-content: center;
	}

	.logo {
		height: 200rpx;
		width: 200rpx;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
		margin-bottom: 50rpx;
	}

	.text-area {
		display: flex;
		justify-content: center;
	}

	.title {
		font-size: 36rpx;
		color: #8f8f94;
	}
</style>

5.2 数据集处理

乱序一下

import random
nums = ''
for i in range(10):
    with open('D:/Hardware/cnn_c90/datasets/num'+str(i)+'.txt', 'r') as f:
        nums += f.read()

with open('D:/Hardware/cnn_c90/datasets/nums.txt', 'w') as f:
    f.write(nums)

datas = []
num = ''
flag = 0
with open('D:/Hardware/cnn_c90/datasets/nums.txt', 'r') as f:
    for line in f.readlines():
        if flag == 0:
            flag = 1
            num = line
        else:
            flag = 0
            num = num+line
            datas.append(num)
            # print(num)
# print(datas)
# 乱序
random.shuffle(datas)
print(datas)

with open('D:/Hardware/cnn_c90/datasets/trans_nums.txt', 'w') as f:
    for data in datas:
        f.write(data)

5.3 训练 

修改一下代码,训练并存储数据集

import numpy as np
from tqdm import trange


class Dataloader:
    """数据读取"""

    def get_data(self, path, cnt):
        """对原始数据进行处理..."""
        images, labels = [], []  # 获得原始数据
        # images = np.reshape(images, (cnt, 28 * 28))  # 28*28的矩阵拉伸为1*784的矩阵
        with open(path, 'r') as file:
            for _ in trange(cnt, desc='读取原始数据: '):
                labels.append(int(file.readline()[0]))  # 读label
                img = []
                for c in file.readline():
                    if c != '\n':
                        img.append(int(c))
                images.append(img)
        images = np.array(images)
        labels = np.eye(10)[labels]  # 单独的标签扩展为[0..9]的矩阵
        print("\033[31m对原始数据进行处理......Done\033[0m")
        return images, labels


def save(wih, who, bih, bho):
    with open('model88.txt', 'w') as file:
        file.write('float wih[20][64] = {')
        for i in wih:
            file.write('{')
            cnt = 0
            for j in i:
                file.write(str(j))
                cnt += 1
                if cnt != 64:
                    file.write(', ')
            file.write('}, ')
        file.write('};\n')

        file.write('float who[10][20] = {')
        for i in who:
            file.write('{')
            cnt = 0
            for j in i:
                file.write(str(j))
                cnt += 1
                if cnt != 20:
                    file.write(', ')
            file.write('}, ')
        file.write('};\n')

        file.write('float bih[20][1] = {')
        for i in bih:
            file.write('{')
            for j in i:
                file.write(str(j))
            file.write('}, ')
        file.write('};\n')

        file.write('float bho[10][1] = {')
        for i in bho:
            file.write('{')
            for j in i:
                file.write(str(j))
            file.write('}, ')
        file.write('};\n')


if __name__ == "__main__":
    # 通过dataloader读取数据
    dataloader = Dataloader()
    images, labels = dataloader.get_data("D:\\Hardware\\cnn_c90\\datasets\\trans_nums.txt", 500)
    # 创建模型
    # 本代码重在快速实现神经网络,因此对模型不做封装
    w_i_h = np.random.uniform(-0.5, 0.5, (20, 64))  # 设置浮点位数float32
    w_i_h = w_i_h.astype('float32')
    w_h_o = np.random.uniform(-0.5, 0.5, (10, 20))
    w_h_o = w_h_o.astype('float32')
    b_i_h = np.zeros((20, 1), dtype=np.float32)
    b_h_o = np.zeros((10, 1), dtype=np.float32)
    # 训练模型
    # - 设置超参数
    learn_rate = 0.01
    nr_correct = 0
    epochs = 2000
    for epoch in range(epochs):
        for img, l in zip(images, labels):
            img.shape += (1,)
            l.shape += (1,)  # 转纵向
            # 前向传播
            # - 输入层->隐藏层
            h_pre = b_i_h + w_i_h @ img
            h = 1 / (1 + np.exp(-h_pre))
            # - 隐藏层->输出层
            o_pre = b_h_o + w_h_o @ h
            o = 1 / (1 + np.exp(-o_pre))
            # - 损失函数计算
            e = 1 / len(o) * np.sum((o - l) ** 2, axis=0)
            nr_correct += int(np.argmax(o) == np.argmax(l))
            # 反向传播
            # - 输出层->隐藏层
            delta_o = 0.2 * (o - l)
            delta_z = (o * (1 - o))
            delta_w_h = np.transpose(h)
            w_h_o += -learn_rate * delta_o @ delta_w_h * delta_z
            b_h_o += -learn_rate * delta_o
            # - 隐藏层->输入层
            delta_h = np.transpose(w_h_o)
            delta_z_2 = (h * (1 - h))
            delta_w_i = np.transpose(img)
            w_i_h += -learn_rate * delta_h @ delta_o * delta_z_2 @ delta_w_i
            b_i_h += -learn_rate * delta_h @ delta_o * delta_z_2
        # 输出精准度
        print(f"Acc: {round((nr_correct / images.shape[0]) * 100, 2)}%")
        nr_correct = 0
    # 展示效果
    while True:
        save(w_i_h, w_h_o, b_i_h, b_h_o)
        index = int(input("输入编号进行预测"))
        img = images[index]
        label = labels[index]
        img.shape += (1,)
        # 前向传播
        h_pre = b_i_h + w_i_h @ img.reshape(64, 1)
        h = 1 / (1 + np.exp(-h_pre))
        o_pre = b_h_o + w_h_o @ h
        o = 1 / (1 + np.exp(-o_pre))
        print(f"label: {label.argmax()}, predicted: {o.argmax()}")

5.4 在C90上再验证

C51上C语言是C90版本

//main.h
#ifndef CNN_C90_MAIN_H
#define CNN_C90_MAIN_H
#define u8 unsigned char
#define u16 unsigned int

float wih[20][64] = {
        {-0.90370303, -1.6227865,  0.006758991,  -0.043860592, -0.90419644,  -1.5324701,  -0.4218245,  0.093345255,  0.25426397,  0.42317036,  0.27248868,  -0.838949,   -2.093729,   -1.0263836,  0.45135808,  -0.33422244,  0.38394472,  -0.2922178,   -0.12184342,  -0.8867094,  -1.8839365,  0.22697262, -0.5545746,  0.07332433,  -0.24611361, 0.86308557,  0.5044917,   0.062405705, -2.4997396,   -0.7037517,  -0.17633998, 0.25601822,  -0.35345513, 0.61995137,  -1.0216911,   -0.330688,   -2.0762396,  -0.7677815,  0.5156707,   -0.16015412, 0.46908054,   -1.9604108,  -0.29565606, -0.457637,    -0.06060111, -0.61806655, 0.84591347,   -0.14021254, 0.09382368,  1.2968239,   -1.2011486,  -2.160614,   -0.81069696, -0.015993768, 0.86204576,  -0.22618859,  -0.17467403, -0.7236278,   0.41246638,  -0.07713144, -0.3216405,  -0.6040587,  -0.31066683, 0.33204365},
        {-0.18481503, 0.02653262, 0.5838272, -0.013661329, -0.19371973, 1.4654182, -0.16194782, 0.3047478, 0.21975555, 0.5717147, 0.909599, -0.9400009, -0.34779134, 1.8818125, -0.49049872, 0.3848227, 0.46840906, -0.26648197, 0.055842612, 0.42987975, 0.931795, 1.8954206, 0.12181818, -0.19418885, 0.6967165, 0.8170402, -0.14423162, 0.32624382, 1.3851455, 1.3319912, -1.1704016, -0.13452211, -0.11261311, -0.41096523, 0.6911238, 2.0207267, 0.007220461, -0.35985875, -0.40490603, -0.4454801, 0.5191932, 1.2247704, -0.4550718, 1.7727829, 0.42461827, -0.7293822, -0.301481, 1.30334, 0.44246933, -1.0345244, 0.84448487, 0.114373475, -1.3343246, 0.42405686, -0.2457504, 1.5834155, 0.53824705, -0.06273292, 0.17574663, 2.1929073, -0.43338934, 1.1680564, -0.9566098, 0.61969316},
        {-0.08448971, -0.06244183, 0.20608118, 1.8847405, 1.8401487, 1.0568348, -0.54447895, -0.42619503, -1.0028598, -0.7916237, 0.7776437, 2.6451797, 1.4491127, 1.3515941, -0.1525097, -0.9111067, -0.35362643, 0.67927057, -0.22971867, 1.7717862, 2.084796, 0.72105414, 0.46293026, -0.3687547, -0.04160447, -1.201657, 0.37202802, -0.97886324, -0.32591164, -2.5771186, -0.95847386, -0.07437611, -0.7089568, 0.32310572, 0.08149235, 0.34042874, 0.32750925, 1.0343381, -1.4179256, -1.8821793, -1.983775, 0.93952405, 1.2394896, 1.4812709, 0.2726556, 0.27329028, -1.2619059, -2.325326, -0.6536865, 0.127664, -0.11920281, 0.70355153, 0.79011184, -0.2506556, -0.8062013, 0.012836788, 0.2328178, -0.068411306, -0.7334768, 1.7404035, 0.8091098, 1.1574407, 2.0655131, 0.47859055},
        {-0.28008026, -0.32492366, 0.13952315, -0.41921338, -0.5023364, -1.2394183, -0.3949447, 0.4893474, -0.57464814, -0.56293637, 0.060509097, 0.039110083, -1.4391131, -0.1481465, -1.0518702, -0.040501382, -0.7300588, -0.5928659, -0.44644672, 0.05788317, -2.3058808, 0.64715236, -0.6008122, -0.12720154, -0.0058052554, -0.34468967, -0.45653287, -0.7098025, -2.8473496, 0.033189263, -0.15926114, -0.19961172, 0.10261695, -0.697879, -0.5346125, -0.33358884, -1.9487486, 0.16498438, -0.33422765, -0.33342296, -0.4264499, -0.28664133, -0.087725945, -0.70558876, -0.35886464, -1.1452191, -0.77950174, 0.27590302, 0.0981756, 0.24444334, -0.42614698, -0.11963545, -0.64529085, -0.121452585, -0.3471749, -1.6613324, -0.5887918, 0.15745597, -0.6374025, -0.5649907, -0.65113693, -0.2332076, -0.11517975, -0.38157293},
        {-0.23989499, 0.10138975, 0.2992003, 1.3381269, 1.050818, -1.1137307, 0.2794603, -0.074104175, 0.35742193, 0.5488519, -0.55003595, 2.6086407, 1.1276761, -1.805448, 0.31624112, -1.0226605, -1.0375922, -1.3576412, 0.6522544, 1.4344914, 2.9542446, -0.8358149, -0.03914513, 0.026673306, -1.3996806, 0.39960584, -0.9237489, -0.595945, 2.6251652, 1.628705, -0.36176848, 0.15991825, -1.8657323, -2.171719, 0.8560495, -0.236917, 1.7283155, -0.077344574, 0.30085137, 0.6763216, 0.5794219, -1.6057203, -2.4041576, 1.7152463, 1.3750616, 2.0734801, 0.43874618, -0.037784614, 0.49655357, -0.007411618, -1.2285866, 1.965862, 1.965069, -0.047366317, -0.106121145, -0.60989666, -1.1255263, -0.39952987, -0.012124025, 0.14022711, -0.8944051, 1.721918, 1.7988228, 0.59003425},
        {-0.10961173, -0.6910169, -0.8075776, -0.74457544, 0.053036503, 0.5468102, -0.04126562, 1.0954581, -1.2138356, -1.4219544, -0.81520236, 0.06809384, -1.6032428, -0.46908212, 0.53823084, 0.8055395, -2.0159664, -0.28746095, -1.1964657, 1.020267, -1.6349722, -1.05356, -0.43398958, 1.2818125, -0.74442136, -0.14068039, -0.018787296, 0.82255083, -0.67692673, 1.908894, 1.9061124, 1.8043677, 0.7050398, 0.81938165, 0.69161284, 0.004269418, 0.5949326, -0.43212122, 0.24324839, 0.8079723, 0.67968553, 0.33509198, 1.1000239, -0.11229033, 0.80615014, -1.2090825, 0.49910334, -0.7847982, -0.5413785, -1.0303452, 0.614484, -0.63636, 0.13785855, 0.6207389, 1.8965181, -1.579762, 0.9521444, -0.5475616, 0.11707687, -0.72770244, -0.6405429, -1.4559705, -0.5141972, -1.5517235},
        {-0.17733128, 0.19089474, -1.78983, -1.081373, 0.007871058, -0.21385096, 1.1410884, 1.7022002, -1.083664, -0.6007506, -1.7507249, -1.5028456, 0.515323, 1.8474102, 2.5001929, 1.363286, -0.2868847, -1.6242372, -2.2344706, -1.8678485, -0.08318619, 4.3101273, 2.8022432, 2.2247834, -0.1304224, -0.022850921, -2.0945702, -1.044108, 0.7445825, 0.5423329, 1.3169034, -0.39946398, -0.078247, -0.3732368, -1.3609457, -0.81833595, 0.5006247, 1.7806033, 0.012465007, 0.40372467, -0.12701432, 0.000118904456, 1.0033633, 0.395385, -1.1447972, -0.32591328, -0.41404682, 0.4038883, 0.060149994, 0.9167585, 0.6525008, 0.05794753, -0.7027614, -1.601301, 0.7910355, 0.75375915, 0.42463538, 1.6335574, 1.1835599, -0.5365144, 0.13045251, -2.008306, -1.5719049, -0.17551544},
        {0.19962265, 0.9040419, -0.41108456, 0.39710236, 0.0035398765, -2.160669, 0.7407019, 0.4443096, 0.66132635, 1.0680324, 0.04655871, -0.12773506, 0.44296113, -2.1415608, 0.053617466, -0.7654339, -0.55000913, 1.5437307, 0.76365995, -1.353169, -1.4267856, 0.26567465, -0.43128905, 0.5080227, -0.48528558, -0.30378145, 0.81417274, -1.0511185, 0.36138734, -0.95792973, 0.8910673, 0.48785105, -0.8904035, -0.48377457, -0.9980029, 0.9112535, 1.2852162, 1.8648367, -1.9632885, -1.9034109, -1.2496066, -0.8188213, -0.3973547, 0.803014, 1.5538423, 1.3795141, -1.9660959, -1.6505208, 0.528507, 0.10899826, -0.9490996, 0.31345358, 2.1494527, 2.2068872, -2.098412, -1.9218686, -0.047385182, -0.45520595, -0.72099555, 0.09160803, -0.68403226, 0.14585863, -2.0611656, -1.38465},
        {0.21106721, -0.5663376, -0.06548628, 1.0173254, 0.5995677, 1.9299055, -0.40289268, 0.024142932, -1.0630907, -0.69513875, 0.25633487, 1.6963174, 0.13189907, 0.82432437, -1.1637928, 0.51822656, 0.29654595, 1.0964646, -0.42981228, 1.1963503, 0.5458766, -1.0733994, 0.062050987, 0.8061106, 0.8928707, 0.41125992, 0.7230523, -1.0004281, -0.888854, -0.15059184, 0.6819982, -0.46539697, 0.40095344, 0.22693694, 2.7507834, -0.9765539, -0.91406816, -0.10050919, -1.1451228, -0.22315933, 0.07438359, 0.3475488, 0.72298115, -0.334541, -0.37646225, 1.568643, -0.08113724, -0.21746147, -0.5260564, -0.0854731, 0.6572121, -0.17562199, 0.112107925, -0.04485716, 0.27897155, 0.24553575, 0.97808814, -1.172291, 0.61723995, -0.026501855, 0.73604804,                                                                            0.41664672,  1.6242247,   0.25898677},
        {-0.53685343, 0.27027404,  -1.1696752,   -0.54213065,  -0.9190853,   0.032319013, -0.34781703, -0.030913185, -0.78295964, -0.12853839, 0.31618023,  -0.13328803, -0.72663397, -1.0652502,  -1.0067376,  0.17512704,   -1.2194577,  0.48107573,   -0.009092109, 1.4251565,   -2.1243641,  -1.5384041, -1.4705309,  -0.23642352, -0.1395358,  -0.2937295,  0.79682684,  -0.6543225,  -1.2825743,   -1.3568541,  -2.046398,   0.38330445,  0.89847195,  -1.926154,   -0.50696033,  0.77036566,  -0.61016494, -0.87539107, 0.7526837,   0.14578561,  -1.0635902,   -1.0321178,  -0.03627153, -0.8321174,   0.124524646, -0.29681563, -0.9913249,   -2.7048078,  -0.2572564,  -0.54465157, 0.3804953,   -0.11894237, 1.3975478,   -0.008739124, -0.8481273,  -1.0363187,   -0.37653932, -0.54376435,  -1.5431976,  -0.12845016, -0.60287046, 0.67853427,  -0.7169106,  -0.4367748},
        {0.55981463,  -1.1641444,  -0.36438262,  0.49444607,   -1.0161186,   -0.4240448,  0.20644581,  -0.62189525,  1.1042548,   1.0055594,   -2.061804,   1.2896538,   -1.2618608,  -0.71236306, -0.47882888, -0.8935898,   1.2771006,   0.97737974,   -3.830193,    -0.25664732, 0.51526153,  0.22470197, -0.50966203, 0.098472625, 1.1269736,   1.911295,    -2.9255779,  0.46280265,  -0.54787755,  -0.4255831,  -0.3026523,  -1.6471986,  0.54709363,  1.3116968,   -1.8969926,   0.4624718,   0.33354384,  -0.18805933, -0.80478185, -0.33723733, 1.6190752,    0.29034436,  -1.6392403,  -0.8218444,   0.45748937,  0.65462816,  -0.4847167,   0.35811973,  0.51573914,  0.56112254,  -0.6837801,  -0.43257478, 0.39162534,  -0.7721747,   0.30401266,  -0.20256715,  -0.12978405, -0.5179902,   0.14528042,  -0.59022826, -0.37835497, -0.6044354,  0.47107688,  -0.048978478},
        {-0.830407,   0.94868946,  -0.053021755, -1.1392072,   1.0258931,    0.47930944,  -0.48818755, -0.53598684,  -1.5286567,  -0.8185924,  -0.44352934, -1.5855994,  1.6295936,   1.5565491,   -0.4594488,  0.14589135,   -1.4498606,  -0.09638974,  -0.44209823,  -1.1448265,  1.1553231,   0.96300036, 0.297711,    -0.33486265, -0.5996388,  -0.12269726, 0.34538034,  0.49682134,  1.7431875,    1.7270001,   0.61359435,  -0.08531431, 1.1194985,   -0.25395283, 0.45225948,   -0.33254093, -0.49142018, -0.09798046, 1.267901,    0.5959748,   -0.49928436,  1.3182635,   1.3479398,   0.22353283,   -2.2125974,  -1.7501084,  -1.570047,    0.7581281,   -1.5386926,  -0.13848302, 1.7402154,   -0.43388996, -1.3112538,  -1.3563507,   -1.4564803,  0.98386186,   -0.6580134,  1.0460929,    0.14173871,  0.014983103, -0.3311887,  -0.7476836,  -1.0842048,  1.324009},
        {0.68236923,  -0.22740963, 0.52448624,   -0.9560157,   -1.2619071,   -0.5293657,  0.011023371, 0.07411865,   1.1045678,   1.1866201,   2.147629,    -1.9600328,  -2.3767853,  -1.2986689,  -0.3469053,  -0.59443754,  1.082573,    1.9886897,    2.172237,     -1.505816,   -3.6129553,  -1.9031959, 0.39116213,  -1.9117448,  -0.15495397, 1.135125,    1.0872302,   -0.38543183, -2.7717972,   -0.39545128, -0.310394,   -1.0636134,  0.1442277,   1.5422833,   1.7938291,    -0.15417123, -1.6487888,  -1.924555,   -0.40387183, -0.41476652, 1.2580423,    0.4767336,   0.24072565,  -1.7017186,   0.9077837,   -1.4571995,  -0.32456416,  0.09176439,  -0.51802343, -0.5290213,  0.2875309,   -1.0347015,  -0.27685422, 0.6302265,    1.1248074,   -0.042384047, 0.8554518,   -1.3651886,   0.30563542,  0.20699824,  0.81288546,  -0.19746333, 0.08890713,  -0.07507332},
        {0.18937048,  0.77593446,  -0.040826846, 0.099822596,  0.57205415,   1.2541627,   1.0013996,   -0.33150408,  -0.6795878,  -1.1206908,  -2.3181443,  -2.2846894,  -0.9032402,  -0.8503272,  -0.80560136, -0.29473165,  -1.2669241,  -1.1187165,   -0.70434606,  -0.06093113, -1.077079,   0.10603313, 0.6304957,   -0.49328232, -0.7709547,  0.09944248,  0.41406354,  -0.48928174, -0.3448364,   0.21150301,  1.2581388,   0.23117699,  -1.0022889,  0.36110094,  -0.41405913,  -0.9597568,  -1.6323218,  -1.9287173,  2.4731805,   0.8826079,   0.1360742,    0.18998435,  0.74651414,  -1.1459556,   -1.4628974,  -0.3990078,  0.8810199,    1.5831354,   -0.2623827,  -0.2921589,  -1.1026233,  -2.7658184,  0.719363,    0.26870668,   0.80756474,  1.0329471,    -0.41529283, 0.0027868305, -0.4184263,  -1.2974318,  -0.30777633, -0.26390573, 1.4770379,   0.9305804},
        {0.36492628,  0.36246073,  -1.4070342,   0.19662166,   -0.36329585,  -1.1904411,  -1.7952766,  -0.54342365,  -0.6235874,  -1.0528649,  -0.47347894, -0.03536505, -0.20266142, -0.13796166, 0.3857793,   0.0076133083, -0.5478579,  -1.1103225,   -1.2550813,   0.49446392,  -0.23652314, 0.28063926, 0.2296214,   -0.8089566,  -0.71379924, -0.8116344,  -0.526067,   0.16365132,  -0.3768348,   -0.18086562, -0.6915715,  -0.02932218, -0.17227441, -0.7566376,  -3.1160433,   0.24207872,  -0.6844323,  0.56241745,  0.7641027,   0.86661625,  -0.724756,    -0.5956835,  -2.906026,   -0.82029223,  -0.5280052,  0.9328222,   0.80980295,   0.8583568,   -0.39354998, -1.3343416,  -2.1438155,  -2.5177836,  0.87976205,  0.89891636,   1.4128779,   0.8357512,    -1.0261161,  -0.23148231,  -0.6294251,  -2.893315,   -1.4009511,  0.06735018,  0.42385456,  0.9046616},
        {0.119352,    0.9772793,   0.6384963,    -2.2011478,   -1.2524942,   -2.037623,   0.24083075,  1.3094004,    0.5211749,   0.12588285,  -0.5309135,  -3.0644922,  -0.46507192, -0.39234996, 1.3498019,   -0.1483634,   1.1638854,   -0.44192886,  -1.13133,     -1.0038191,  -0.4557811,  -1.4647924, 0.84541106,  -0.01636926, 0.24002273,  -1.6808751,  -0.59616137, -1.3520907,  1.7963015,    -3.0386841,  0.6586133,   0.7790693,   0.1513685,   -0.9849836,  -1.7251946,   0.044953015, -0.5753291,  -0.7783064,  0.18381253,  0.40621015,  -1.0306864,   0.5543329,   -0.46208987, -0.020203413, -0.37550324, -1.5528892,  -0.7203983,   0.498279,    -0.9656106,  -0.69982404, -0.32651168, 0.11979463,  -2.2027533,  -0.31584767,  0.024807813, 0.45917353,   0.21653223,  0.83372307,   0.27598244,  0.09120625,  0.45691663,  -0.42203763, -2.0963845,  -0.31434712},
        {0.9694672,   -0.21618915, 1.2000359,    1.4444586,    0.12763503,   -0.44007143, -0.52253795, 0.19511013,   0.4814508,   0.69288373,  0.80209935,  1.1408228,   -0.5770815,  -0.69757074, -1.8381656,  -0.93887925,  0.29420453,  0.66520464,   0.64318985,   0.1131627,   2.4804077,   -1.730284,  -2.6548784,  -1.5249332,  0.2816821,   0.1806157,   -0.20500597, -0.35767922, 1.2063946,    -2.2370265,  -1.7448623,  -1.3403648,  -0.67782694, -0.29558426, -0.053324327, -0.43356156, -0.38445562, -1.290601,   -0.55036163, -0.7919362,  -0.8212288,   0.19941059,  0.20044178,  -0.50659764,  -0.6866085,  -0.9537341,  -0.022947935, 0.6344333,   0.04698309,  0.38625598,  0.21129276,  -0.14701809, -0.9243069,  -0.40494016,  -1.9157158,  -1.2349731,   -0.16974495, -0.7973496,   -0.49334237, 0.33268788,  -0.30658814, -0.24022289, -0.8470375,  -0.77296454},
        {1.3792558,   0.3600045,   0.5468229,    -0.08909639,  -0.8382965,   -0.9029627,  -1.28078,    -0.63418335,  -0.84982574, 0.016387843, 1.9495778,   0.89398104,  -0.2777039,  -0.7896938,  -0.81972706, -0.38913116,  0.3948264,   1.4004004,    1.5675489,    0.7240448,   -0.2528365,  -0.7263563, -0.9510525,  -0.688148,   -0.06977625, -0.3690885,  0.5533377,   0.9727561,   -0.029515458, -0.24345532, -0.21802844, -0.18032533, -0.47439632, -1.7230483,  -1.3562231,   -0.6619784,  0.88759995,  1.3869495,   1.1429521,   0.654589,    -0.031451512, -1.5425696,  -1.8436652,  -1.8672744,   1.3021322,   1.9544067,   0.5191355,    1.3214257,   -0.06958157, -0.72234243, -1.9390411,  -1.3050647,  1.0565604,   0.9678962,    0.98017687,  1.3023964,    -1.5278738,  -0.23616996,  -1.585107,   -2.2699115,  -0.53853023, 0.8132038,   0.7590706,   0.73317206},
        {-0.8187737,  0.467179,    -0.73361504,  -0.3407762,   -0.26293063,  -1.0500106,  0.4947593,   -0.21366,     0.18561968,  -0.16594592, 0.14173563,  1.6936625,   1.7120253,   -1.424868,   0.76361907,  -0.83822757,  -0.17544578, -0.011800428, 0.91934395,   1.3541225,   -1.2425042,  -0.156594,  0.7947865,   -0.48207992, 1.3447042,   -0.25073656, 1.4096646,   2.8795881,   -0.5136539,   -1.0368112,  -0.4362688,  0.7306975,   -0.09019608, 0.39012805,  0.5691338,    1.162135,    1.8983095,   -0.36212087, -0.7184063,  -0.27831712, -1.7150927,   0.594438,    1.2943473,   0.41104338,   0.46464878,  1.0006706,   0.35518378,   -2.0451317,  -1.5307034,  0.8499877,   1.1447632,   2.1680858,   1.1034998,   1.1369995,    -1.002666,   -0.83564883,  0.9039399,   0.22262073,   -0.12268762, 2.3627865,   0.3677706,   0.73920745,  0.026835948, -1.3977033},
        {1.2600089,   0.067648366, 0.9185,       0.07245796,   0.033649117,  1.0299469,   0.23839106,  -0.29191506,  1.7282989,   -0.31482607, 0.32536986,  -0.17893313, -1.0621817,  0.55509955,  2.07455,     -0.016044078, 2.167265,    -0.04853997,  1.5335227,    -1.4178636,  0.16353802,  0.87930965, 0.4386904,   0.12409826,  0.60591596,  0.72009134,  0.57418287,  -1.4734936,  -0.58911437,  1.4214422,   -1.1867632,  0.033941027, 0.6741393,   3.6147294,   -0.904962,    -0.13489676, -1.5109322,  0.60367405,  0.7773489,   -1.0289242,  2.8056302,    -0.29122135, -2.1291616,  -0.6375071,   -0.08076189, 1.2950406,   0.92092115,   -0.33424875, 0.9759254,   0.6305621,   -1.8993558,  -1.6752487,  1.627763,    -0.37919223,  1.0123148,   0.53763217,   0.2818548,   0.41636023,   -0.42767346, -1.1393545,  0.3400047,   -0.78577006, 0.9938756,   0.72512734},};
float who[10][20] = {{-0.4391785,   0.45936167,  3.009325,    -0.9940405,   -0.94923043, 1.531904,   4.1249785,    1.7364545,   3.426625,    -0.18424246, 0.4717404,   2.1033034,   -0.2697841,  2.6408699,   -0.46264768, 0.025534296, -0.9158153, -0.6739721,  3.0778866,   1.6586876},
                     {2.1256936,    0.048414122, 1.0153224,   3.4136572,    -0.2511183,  1.4299101,  2.8762167,    1.1248986,   -0.11606479, 3.0881038,   0.052111022, 2.1941385,   -0.23256095, 2.2201092,   3.4117224,   3.491359,    1.3918484,  0.43595034,  0.57193816,  -0.17133746},
                     {1.1668886,    3.865467,    -0.80501586, -0.121559255, -1.1265839,  1.9611652,  4.4882703,    -0.62969303, 0.579606,    -0.9351614,  0.72108424,  3.6922376,   0.892528,    0.4956507,   0.10175876,  2.211653,    0.7072504,  -0.15880612, -0.8451216,  3.3263876},
                     {0.5671747,    0.18518089,  -0.48920166, 1.0538653,    3.1359792,   2.555256,   4.684817,     3.1064205,   0.21195829,  -0.4834232,  2.170211,    -0.17987826, 0.16602038,  -0.31725043, -0.24240737, 3.5321064,   0.55264086, -0.5718727,  3.2886224,   -0.090337865},
                     {0.14142717,   2.3623872,   2.9886448,   0.6653042,    3.047261,    1.0545291,  -0.8086263,   3.9324226,   0.9444289,   2.4637024,   0.2810431,   0.6929236,   1.3579776,   -0.4159053,  0.38797346,  0.16914849,  2.5964139,  2.6959612,   3.4867737,   -0.7064337},
                     {2.7108688,    0.25739613,  -0.3068497,  1.7099086,    -0.43095756, 3.103455,   -0.017121702, 2.7222502,   2.2039282,   2.1615596,   0.05489299,  -1.2183563,  2.6329393,   1.9977432,   2.0274868,   0.52042073,  -1.3191999, 2.4624686,   3.1253536,   3.459109},
                     {-0.04492686,  1.1284969,   0.77378005,  -0.41819206,  3.5430558,   1.6225992,  1.4619355,    -0.14924008, 1.6083195,   -0.76981723, 1.7788991,   1.2977281,   -0.78710324, 2.644774,    2.7490668,   -0.82152945, 0.578732,   3.278684,    0.3166879,   5.1451254},
                     {2.5369549,    -0.66505665, 0.20186862,  2.6726503,    0.725227,    -0.3420248, 0.1468595,    0.93273944,  1.4360497,   0.58014476,  3.4209948,   0.25468013,  3.7943187,   0.060351912, 0.696795,    0.851926,    2.9738708,  0.89314353,  -0.47824088, 1.0113764},
                     {-0.041543253, 3.6848586,   3.2534397,   -0.674382,    4.09213,     2.284207,   0.92676896,   -1.2109576,  1.7128725,   -0.39194766, -0.17690873, 3.4443536,   0.09490261,  0.62224287,  -0.8757461,  -1.2177278,  0.25689146, 0.03383527,  4.510749,    2.2395403},
                     {-1.2705529,   2.346738,    0.17966743,  0.7468895,    1.8190755,   3.4053454,  -0.040168725, 0.027062561, 2.586291,    -0.38730597, -0.19242558, -0.11667485, 3.5816004,   -1.3588527,  -0.54770744, 2.051337,    0.75088567, 2.4228947,   2.309,       0.7056862},};
float bih[20][1] = {{3.0684712},
                    {-5.4074607},
                    {-2.0961134},
                    {5.402638},
                    {-3.9972277},
                    {-2.3793092},
                    {0.79371244},
                    {-0.56251353},
                    {-3.446082},
                    {3.914923},
                    {-0.787332},
                    {-1.0958598},
                    {-0.5936966},
                    {0.263845},
                    {4.3508554},
                    {4.3272176},
                    {3.4176707},
                    {-2.0772617},
                    {-5.3518133},
                    {-3.6845343},};
float bho[10][1] = {{-10.985425},
                    {-14.943932},
                    {-12.863759},
                    {-12.288082},
                    {-14.769943},
                    {-14.0065365},
                    {-13.475397},
                    {-11.442304},
                    {-13.062471},
                    {-9.910325},};
u8 images[500][8];
u8 labels[500];
#endif //CNN_C90_MAIN_H
//main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "main.h"
float my_exp(float x) {
    x = 1.0f + x / 1024;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    return x;
}
float h_pre[20][1], h[20][1], o_pre[10][1], o[10][1];
void reset() {
    memset(h_pre, 0, 20 * 1 * sizeof(float));
    memset(h, 0, 20 * 1 * sizeof(float));
    memset(o_pre, 0, 10 * 1 * sizeof(float));
    memset(o, 0, 10 * 1 * sizeof(float));
}
void get_h_pre(const u8 *img) {
    int i, j;
    for (i = 0; i < 20; i++) {
        for (j = 0; j < 64; j++) {
            if ((img[j / 8] >> (7 - j % 8)) & 0x01) {
                h_pre[i][0] += wih[i][j];
            }
        }
        h_pre[i][0] += bih[i][0];
    }
}

void get_h() {
    int i = 0;
    for (i = 0; i < 20; i++) {
        h[i][0] = 1.0f / (1 + my_exp(-h_pre[i][0]));
    }
}

void get_o_pre() {
    int i, j;
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 20; j++) {
            o_pre[i][0] += who[i][j] * h[j][0];
        }
        o_pre[i][0] += bho[i][0];
    }
}

void get_o() {
    int i = 0;
    for (i = 0; i < 10; i++) {
        o[i][0] = 1.0f / (1 + my_exp(-o_pre[i][0]));
    }
}

u8 get_res() {
    u8 res = 0, i;
    float cor = 0;
    for (i = 0; i < 10; i++) {
        if (cor < o[i][0]) {
            cor = o[i][0];
            res = i;
        }
    }
    return res;
}
void get_data() {
    int i, j;
    char label_str[3];
    char image_str[66];
    FILE *fp = fopen("D:\\Hardware\\cnn_c90\\trans_nums.txt", "r");
    if (fp == NULL) {
        printf("\033[31mERROR: %d %s\n\033[0m", errno, strerror(errno));
        exit(-1);
    }
    for (i = 0; i < 500; i++) {
        fgets(label_str, 3, fp);
        labels[i] = label_str[0] - '0';
        fgets(image_str, 66, fp);
        for (j = 0; j < 64; j++) {
            if (image_str[j] == '1') {
                images[i][j / 8] |= 0x80 >> (j % 8);
            }
        }
    }
    printf("数据读取完成\n");
}
int main() {

    int i = 0;
    //记录正确数量
    int cor = 0;
    //读取数据
    get_data();
    //测试
    for (i = 0; i < 500; i++) {
        reset();
        get_h_pre(images[i]);
        get_h();
        get_o_pre();
        get_o();
        if (labels[i] == get_res()) {
            cor++;
        }
    }
    printf("acc: %f", cor / 500.0);
    return 0;
}

跑完一看,很好啊,acc还是90%多,此时的还不知道后面会发生什么

5.5 51上的识别代码

//cnn.h
#ifndef _CNN_H_
#define _CNN_H_

#include "lcd1602.h"
#include "public.h"
void get_res();

#endif
//cnn.c
//模型贴过来
float xdata h_pre[20][1], xdata h[20][1], xdata o_pre[10][1], xdata o[10][1];

void reset() {
    u8 i;
    for (i = 0; i < 20; i++) {
        h_pre[i][0] = 0;
        h[i][0] = 0;
    }
    for (i = 0; i < 10; i++) {
        o_pre[i][0] = 0;
        o[i][0] = 0;
    }
}

void get_h_pre(const u8 *img) {
    u8 i, j;
    for (i = 0; i < 20; i++) {
        for (j = 0; j < 64; j++) {
            if ((img[j / 8] >> (7 - j % 8)) & 0x01) {
                h_pre[i][0] += wih[i][j];
            }
        }
        h_pre[i][0] += bih[i][0];
    }
}

void get_h() {
    u8 i = 0;
    for (i = 0; i < 20; i++) {
        h[i][0] = 1.0 / (1 + exp(-h_pre[i][0]));
    }
}

void get_o_pre() {
    u8 i, j;
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 20; j++) {
            o_pre[i][0] += who[i][j] * h[j][0];
        }
        o_pre[i][0] += bho[i][0];
    }
}

void get_o() {
    u8 i = 0;
    for (i = 0; i < 10; i++) {
        o[i][0] = 1.0 / (1.0 + exp(-o_pre[i][0]));
    }
}

// 识别
void get_res(const u8 *img) {
    u8 res = 0, i;
    float cor = 0;
    char xdata pre[10], pro[10];
    reset();
    get_h_pre(img);
    get_h();
    get_o_pre();
    get_o();
    for (i = 0; i < 10; i++) {
        if (cor < o[i][0]) {
            cor = o[i][0];
            res = i;
        }
    }

    sprintf(pre, "Pre: %u", res);
    LCD_ShowString(1, 1, pre);
    sprintf(pro, "Pro: %.2f%%", cor * 100);
    LCD_ShowString(2, 1, pro);
}

5.6 编译运行

编译没问题,下载运行一看,咦?不对,状态和预想的不一样

找了半天程序的问题,最后发现code超了,最多8000

放在xdata里面,code也涨,甚至更多?

然后删改代码,去掉串口,<stdio.h>也不需要了

去掉<math.h>的exp,用自己的

发现调用系统库真耗费空间,虽然去掉后还是超出

修修改改改了一天,还是9000+

最后没办法,打算删去隐藏层,重新跑

5.7 再次训练

各种训练,顶天也就76%的正确率了

import numpy as np
from tqdm import trange


class Dataloader:
    """数据读取"""

    def get_data(self, path, cnt):
        """对原始数据进行处理..."""
        images, labels = [], []  # 获得原始数据
        # images = np.reshape(images, (cnt, 28 * 28))  # 28*28的矩阵拉伸为1*784的矩阵
        with open(path, 'r') as file:
            for _ in range(cnt):
                labels.append(int(file.readline()[0]))  # 读label
                img = []
                for c in file.readline():
                    if c != '\n':
                        img.append(int(c))
                images.append(img)
        images = np.array(images)
        labels = np.eye(10)[labels]  # 单独的标签扩展为[0..9]的矩阵
        print("\033[31m对原始数据进行处理......Done\033[0m")
        return images, labels


def save(wio, bio):
    with open('model88.txt', 'w') as file:
        file.write('float w_i_o[10][64] = {')
        for i in wio:
            file.write('{')
            cnt = 0
            for j in i:
                file.write(str(j))
                cnt += 1
                if cnt != 64:
                    file.write(', ')
            file.write('}, ')
        file.write('};\n')

        file.write('float b_i_o[10][1] = {')
        for i in bio:
            file.write('{')
            for j in i:
                file.write(str(j))
            file.write('}, ')
        file.write('};\n')


wio, bio, a = None, None, 0

if __name__ == "__main__":
    # 通过dataloader读取数据
    dataloader = Dataloader()
    images, labels = dataloader.get_data("trans_nums.txt", 500)
    # 创建模型
    # 本代码重在快速实现神经网络,因此对模型不做封装
    w_i_o = np.random.uniform(-0.5, 0.5, (10, 64))
    w_i_o = w_i_o.astype('float32')
    b_i_o = np.zeros((10, 1), dtype=np.float32)
    # 训练模型
    # - 设置超参数
    learn_rate = 0.01
    nr_correct = 0
    epochs = trange(20000)
    for epoch in epochs:
        for img, l in zip(images, labels):
            img.shape += (1,)
            l.shape += (1,)  # 转纵向
            # 前向传播
            # - 输入层->o
            o_pre = b_i_o + w_i_o @ img
            o = 1 / (1 + np.exp(-o_pre))
            # - 损失函数计算
            e = 1 / len(o) * np.sum((o - l) ** 2, axis=0)
            nr_correct += int(np.argmax(o) == np.argmax(l))
            # 反向传播
            # - 输出层->
            delta_o = 0.2 * (o - l)
            delta_z = (o * (1 - o))
            delta_w_i = np.transpose(img)
            w_i_o += -learn_rate * delta_o @ delta_w_i * delta_z
            b_i_o += -learn_rate * delta_o
        acc = round((nr_correct / images.shape[0]) * 100, 2)
        epochs.set_postfix(acc=f"{acc}%", max=f"{a}%")
        nr_correct = 0

        if a < acc:
            a = acc
            wio = w_i_o
            bio = b_i_o
            if a >= 70:
                save(wio, bio)

    # 展示效果
    while True:
        # save(w_i_h, w_h_o, b_i_h, b_h_o)
        index = int(input("输入编号进行预测"))
        img = images[index]
        label = labels[index]
        img.shape += (1,)
        # 前向传播
        o_pre = b_i_o + w_i_o @ img.reshape(64, 1)
        o = 1 / (1 + np.exp(-o_pre))
        print(f"label: {label.argmax()}, predicted: {o.argmax()}")

5.8 再次验证

76%的正确率,只能这样咯

//main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "main.h"

float my_exp2(float x) {
    float t = x * 1.442695041f;
    int m = 0;
    float n = 0;
    float tmp_n, j, result;
    int i;
    m = (round)((int) (t * 2.0) / 2);
    n = t - m;
    m = (m + 127) << 23;
    n = n * 0.693147181f;
    tmp_n = n;
    j = 1;
    result = 1 + n;
    for (i = 2; i < 7; i++) {
        j = j * i;
        tmp_n = tmp_n * n;
        result += tmp_n / j;
    }
    return *(float *) &m * result;
}

float my_exp(float x) {
    x = 1.0f + x / 1024;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    x *= x;
    return x;
}

void get_data() {
    int i, j;
    char label_str[3];
    char image_str[66];
    FILE *fp = fopen("D:\\Hardware\\programs\\cnn_c90\\trans_nums.txt", "r");
    if (fp == NULL) {
        printf("\033[31mERROR: %d %s\n\033[0m", errno, strerror(errno));
        exit(-1);
    }
    for (i = 0; i < 500; i++) {
        fgets(label_str, 3, fp);
        labels[i] = label_str[0] - '0';
        fgets(image_str, 66, fp);
        for (j = 0; j < 64; j++) {
            if (image_str[j] == '1') {
                images[i][j / 8] |= 0x80 >> (j % 8);
            }
        }
    }
    printf("数据读取完成\n");
}

float no_pre[10][1], no[10][1];

void reset() {
    int i;
    for (i = 0; i < 10; i++) {
        no_pre[i][0] = 0;
        no[i][0] = 0;
    }
}

void get_no_pre(const u8 *img) {
    int i, j;
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 64; j++) {
            if ((img[j / 8] >> (7 - j % 8)) & 0x01) {
                no_pre[i][0] += w_i_o[i][j];
            }
        }
        no_pre[i][0] += b_i_o[i][0];
    }
}

void get_no() {
    int i = 0;
    for (i = 0; i < 10; i++) {
        no[i][0] = 1.0f / (1 + my_exp(-no_pre[i][0]));
    }
}

u8 get_nres() {
    u8 res = 0, i;
    float cor = 0;
    for (i = 0; i < 10; i++) {
        if (cor < no[i][0]) {
            cor = no[i][0];
            res = i;
        }
    }
    return res;
}

int main() {

    int i = 0;
    //记录正确数量
    int cor = 0;
    //读取数据
    get_data();
    //测试
    for (i = 0; i < 500; i++) {
        reset();
        get_no_pre(images[i]);
        get_no();
        if (labels[i] == get_nres()) {
            cor++;
        }
    }
    printf("acc: %f", cor / 500.0);
    return 0;
}

5.9 可以放下的识别代码

//cnn.c
#include "cnn.h"

// 模型参数
float code w_i_o[10][64] = {
    {0.5664128, -0.21377318, -0.9949012, -1.5381784, -0.6744786, 0.031389937, 0.17588668, -0.47555494, -1.0540706, -0.83008116, -1.1026632, 0.2791996, 1.4949312, 0.8007128, 0.17226571, -0.6794696, 0.33934882, -0.41205436, -0.85786813, -0.885778, -0.22843638, 0.22343862, 0.50407225, -0.71781003, 1.0171996, -0.09237784, -1.0800514, -2.699908, -3.1323385, -1.5755824, 2.300938, 1.5855157, -1.2364568, -0.8945054, -0.6154064, -0.117638245, -0.21715613, 0.038885966, -0.59815556, 0.24405, -2.00755, -0.75985026, 0.43208393, 0.17077754, -0.37598416, 0.0685567, -1.2036531, -0.60508895, 0.4161404, 0.8650985, -0.6206283, -1.0404283, -1.273805, -1.3590841, -0.7722982, 0.76257795, 0.13840488, -0.32380986, -0.25333732, -0.014944064, -0.56606346, -0.65280145, -0.36057612, 0.019987313},
    {-0.1287646, 1.7691618, -1.1548091, -0.66205424, -0.46131417, 0.13660304, -0.6822341, -0.1587507, -0.15591387, -1.0338596, 0.48730052, -1.1988409, -0.16180669, -0.31696317, 0.18199006, -0.12097158, -2.1686668, -0.437815, -1.114581, 0.86003315, -0.87250894, 0.3907029, -0.33462653, -0.6833954, -0.10904898, -0.2668449, 0.6546389, -0.9240991, -0.012335212, -0.84346825, -0.25090387, 0.5224132, 1.4049937, -0.7072402, -0.9833269, -0.43207213, -0.6533614, 0.09074907, 0.096326075, 0.05208772, -2.737896, -1.0028173, -0.6560741, -1.1592655, -1.2793996, -1.1738114, -0.79059035, -0.110063724, -0.4057571, -0.42603657, 0.48673856, -0.25040984, -0.54386926, -0.05663645, 0.0633362, -0.00384197, -0.27499703, 1.158131, -0.32893884, -0.6537069, -0.37018344, -0.5214341, -0.20541938, -0.04008949},
    {0.45087922, -0.44029087, 0.02818912, -0.9861958, -0.14602016, 0.6199761, 0.26170665, 0.4773626, 0.19992071, 0.39806223, 0.19171926, -1.898419, -0.8119795, 2.0020351, 0.26241535, 0.4530684, 0.44913626, -0.025234446, -0.7138027, -2.7908347, 0.4583805, 1.7096424, 0.7780832, 0.3040807, 1.2149675, 0.5965316, -1.2294679, -1.0392593, 1.815863, 0.345495, -0.31170833, 0.7029222, 1.2379982, -0.74947476, -0.9227225, -0.28138041, -0.36642802, -0.7547913, 0.59573627, 0.20162958, 0.6739312, 0.21116792, 0.695258, 0.45859963, -1.9335011, -1.6994677, 0.32537702, 0.38245207, -0.6413663, 0.31038445, 0.17677906, -1.1035521, -1.5025705, -0.77915066, 0.4588546, 1.1508449, 0.23090373, -0.16805865, -0.06785368, 0.39476854, -0.5246919, -0.12579326, -0.1466648, 0.31628335},
    {-0.27442276, 0.5376627, -0.029169874, -1.9675182, 0.2569605, -2.526442, 0.4888193, 0.3914235, -0.36344862, -0.076950766, -0.74662167, -1.6026591, 0.4519849, -2.101405, 0.67674446, 0.049886927, -1.1595732, -0.5162468, 0.16083445, -2.5138109, 0.07903132, -1.7985072, 0.8392261, 0.74122584, -1.826293, -0.2513942, -0.8832548, -1.7359478, 1.0858169, -1.7366488, 0.89563257, 0.6370047, -0.73518175, -0.60361, -0.7951568, -0.68310374, 0.5708151, -0.14829913, -1.1781907, 0.060677845, -0.6314977, -0.4661686, -0.62409884, 1.0835748, -0.28249732, 0.13847184, -1.8021599, -0.4948054, -1.1481088, 0.29535308, -0.6657051, 1.5209445, -0.8130289, -0.3716246, 0.08509089, -0.98847365, 0.042415492, 0.36641946, 0.37069294, -0.8917385, -0.062407386, -0.43371075, -1.2039088, -0.9063634},
    {1.0098052, 0.9638526, 1.0310292, 1.1218865, 0.13098039, -0.44242826, 0.14832462, 0.093124725, 0.32978576, 1.69877, 1.8342276, 1.6463071, 1.6425794, -0.07154793, -1.5220383, -0.81401753, -1.5759354, 1.7026329, 1.4346062, 2.705223, 1.0447, -0.776469, -1.8811721, -1.8876435, -0.5229143, -0.29949275, 1.6944939, 1.7749103, 1.6006886, -0.75252247, -0.062181108, -0.13629967, -0.37296852, -1.178062, 0.6418236, 2.5275185, 2.1645277, 1.4632483, -1.1301785, -1.8371595, -1.809058, -0.48071632, 0.6477235, 2.1100097, 1.7931606, 1.3773451, -0.5475025, -0.5024947, 1.337733, -0.36974832, 0.66300565, 1.5456525, 2.2928379, 1.9860828, -1.4773195, 0.0668749, 0.09991437, -0.41769972, -1.1866688, 2.8109226, -0.14803259, 1.9053943, -0.9735171, -0.3339023},
    {-0.24487436, -0.42400324, -0.30249482, -0.12105501, -0.29765686, -0.38017425, 0.13065003, 0.21761602, -0.35170588, -0.78531325, 0.04976741, -0.42394328, -0.73761, -0.9301451, -0.15310352, -0.055574946, -0.6484745, -0.14658038, 0.5253345, 0.91049427, -3.101725, -0.23344709, 0.16033864, 0.14616747, -0.63162464, 0.11460595, 1.7047725, -0.7411919, -3.6615617, -0.19269247, -0.26489735, -0.098733775, 0.42233798, 1.9236151, -1.0911032, -0.05932005, -3.2683613, 0.47177082, 1.3705348, -1.6343354, 0.63776124, -2.0953922, -0.6536648, -0.54609483, -0.3478762, 0.9674527, 0.21019526, -2.1315691, -0.5902906, -0.103782475, -1.0732667, -0.32061344, -0.10739035, 0.5160776, 1.0286543, -1.2274673, 0.2536698, -1.5707686, -0.46092844, -1.0782149, 0.041600972, 0.13881266, 0.19510913, -0.47600266},
    {0.16206253, -0.41137853, -0.30896583, 0.15597634, -0.2671143, -0.490882, -0.19013932, -0.17649114, -0.14425853, -0.74385893, -0.27669305, 0.5229035, 0.3223738, 0.46223292, 0.76378363, 0.35678196, -0.1909429, -0.59805137, -0.034946203, 0.2438756, 1.2589049, 1.0627805, -0.008614447, -0.47932085, -0.15413885, 0.5135362, 0.055834696, -0.50514984, 0.40221038, 1.3746467, -0.3913967, -0.6308095, 0.6262, 1.654139, -1.9290391, -0.60847926, -0.17292087, 0.22339667, 0.860688, 0.5917775, 2.4611459, -0.07645186, -4.089945, -0.1365905, 0.35009843, 0.83978295, 0.23540232, 0.8632825, 0.16462836, -0.25641006, -3.3173764, 0.019710872, 0.477034, 0.22136706, 0.54076093, 0.2991061, -0.79096633, 0.06622481, -1.6888721, -1.727642, -0.40511695, -0.1578727, 0.4934376, 0.8478045},
    {0.8886541, -0.850461, -0.4818631, -0.6828393, -0.97116846, -0.7863555, -0.046479154, -0.49556616, 1.0759739, 0.7518069, -2.3420458, -0.75652367, -1.1588994, -0.9947721, -0.7090172, -0.45524618, 1.5364089, 0.92022544, -0.22594912, -1.223866, -1.4031786, -1.4002037, -1.4645462, -0.92796814, 1.3273005, 1.870906, -1.0081747, -1.4168409, -2.4580073, -2.1507187, -1.7504948, -1.477973, -1.0788976, 0.65131307, 0.6671654, -1.0078651, -1.3393376, -0.81958896, -1.1687428, -0.62359655, 0.44632775, -0.6483983, -0.9376602, -1.204626, -0.34700435, -0.13605659, 0.6364287, 1.5620615, 0.19357407, 1.072611, -0.3364704, -0.5714024, -0.7175412, -0.97793233, -0.6831355, -1.0120184, 0.10754612, -0.72486687, 0.68247044, -0.55654883, -0.51798296, -1.3358388, 0.40848798, 0.05566829},
    {0.009082103, -0.8962332, 0.11980997, 0.33128145, 0.79228425, 1.748759, 1.5948095, -0.2304744, 0.030942554, -1.2351195, -0.07378349, 1.380836, 1.183818, 1.141433, 1.2474294, 0.6687325, -0.47671166, 0.20786946, 0.013008165, 2.334073, 2.4743376, 0.6065397, 1.4038479, 0.35357246, -0.1728394, 0.3911426, 1.935861, 3.1084993, 2.2066686, 2.236507, 0.101251304, 1.0822725, 0.9802556, 0.92733866, 2.360789, 1.7853508, 2.5690093, 0.6132833, 0.46499756, 0.025977813, 0.56731886, 1.3453466, 1.5029863, 1.4470205, 0.42743844, 0.93358517, 0.14194085, -0.9889256, 0.47468865, 0.90948784, 1.7025644, 1.3043516, -0.379508, 0.15513512, 0.38815066, 0.042103507, 1.0232406, 0.81580967, 1.2687304, 1.618544, 0.3717951, -0.31052575, 0.66586, 0.026752843},
    {1.1892788, 0.8457045, 1.8120186, -0.9023276, -1.5560519, 0.016546793, -0.24336892, 0.22750868, 0.33744442, -1.3129724, 1.0549358, -0.39500278, -0.762012, -0.40559182, -0.98795485, -0.48150063, 0.3036769, 0.11784292, 0.5135058, 1.8106189, -0.83792245, -1.5639293, -0.2018165, 0.5286669, 1.076017, 0.49631706, 0.06660596, 0.7501726, -1.1053836, -0.30826923, -0.28328136, -0.2446471, -0.60855806, -0.5883348, 2.3820124, -0.7981061, 1.6157442, -0.7148589, 0.10950754, 0.001185905, 0.3636903, 1.6486617, 0.84226847, -1.3624489, 0.5755647, 0.4186654, -0.21985774, 0.36796582, -0.5501688, 0.023035761, 0.71817553, 0.11063999, -1.3321682, 0.5219533, 0.39590842, -0.5938355, 0.66772026, 0.10669082, -0.09691508, -0.8214123, -0.014642326, -0.21960828, -0.3641557, -0.63633627},
};
float code b_i_o[10][1] = {
    {1.7617584},
    {1.8119161},
    {-3.708471},
    {1.4891008},
    {-13.087248},
    {-0.25907508},
    {-4.3405833},
    {1.7190828},
    {-18.712358},
    {-4.918423},
};

float xdata no_pre[10][1], no[10][1];

// void get_no_pre() {
//     int i, j;
//     for (i = 0; i < 10; i++) {
//         for (j = 0; j < 64; j++) {
//             if ((GLED_PER_COL_DATA[j / 8] >> (7 - j % 8)) & 0x01) {
//                 no_pre[i][0] += w_i_o[i][j];
//             }
//         }
//         no_pre[i][0] += b_i_o[i][0];
//     }
// }

// void get_no() {
//     int i = 0;
//     for (i = 0; i < 10; i++) {
//         no[i][0] = 1.0f / (1 + my_exp(-no_pre[i][0]));
//     }
// }

void get_res() {
    u8 res = 0, i, j;
    float cor = 0;

    char str[16] = "Res:    ";

    for (i = 0; i < 10; i++) {
        no_pre[i][0] = 0;
        no[i][0] = 0;
    }
    // get_no_pre();
    for (i = 0; i < 10; i++) {
        for (j = 0; j < 64; j++) {
            if ((GLED_PER_COL_DATA[j / 8] >> (7 - j % 8)) & 0x01) {
                no_pre[i][0] += w_i_o[i][j];
            }
        }
        no_pre[i][0] += b_i_o[i][0];
    }
    // get_no();
    for (i = 0; i < 10; i++) {
        no[i][0] = 1.0f / (1 + my_exp(-no_pre[i][0]));
    }
    for (i = 0; i < 10; i++) {
        if (cor < no[i][0]) {
            cor = no[i][0];
            res = i;
        }
    }
    str[5] = res + '0';
    str[8] = (int)(cor * 10) % 10 + '0';
    str[9] = (int)(cor * 100) % 10 + '0';
    str[10] = '.';
    str[11] = (int)(cor * 1000) % 10 + '0';
    str[12] = (int)(cor * 10000) % 10 + '0';
    str[13] = '%';
    str[14] = '\0';
    LCD_ShowString(1, 1, str);
}

6、跑通

//main.c
#include "ir.h"
#include "lcd1602.h"
#include "leds.h"
#include "public.h"
//
u8 GLED_PER_COL_DATA[8] = {0};
u8 point = 0;

void init() {
    // leds 使用P0 P34 P35 P36
    // ir使用 数据接收P32 外部中断1 P33
    ir_init();
    // lcd1602 使用P26 P25 P27
    LCD_Init();
}

void main() {
    init();
    LCD_ShowString(1, 1, "START...");
    while (1) {
        led_display();
    }
}

最后总算是跑通了,效果还算理想

可能因为数据集和准确度的原因,2、9的字形会识别成8

补:啊啊啊,突然意识到我犯蠢了;隐藏层不该删掉,应该在保持较高acc的基础上,逐步减少隐藏层大小,直到满足内存要求。。。QAQ,果然还是太小白了,还是得多学

;