https://blog.csdn.net/qq_41126242/article/details/145050324

Nor Flash和Nand Flash

特性 Nor Flash Nand Flash
读写速度 高速,支持随机读写(类似于RAM) 较慢,按块顺序读写
写入速度 较慢 快速
擦除速度 较慢,擦除整个块(约5秒) 快速,擦除块(约4毫秒)
擦除次数 较少,一般为10000次左右 较多,可达100万次以上
可靠性 高,不易发生位反转 一般,易发生位反转,需使用ECC/DCC算法
容量 较小,通常在1MB到32MB之间 较大,通常在8GB到512GB之间
成本 较高 较低
接口 类似SRAM,有独立地址和数据总线 使用I/O总线串行访问
擦除方式 按字节擦除 按块擦除
应用领域 存储代码、关键数据、嵌入式系统等 存储大量数据,如固态硬盘、U盘等
执行方式 支持片上执行(XIP) 需要先将数据读入RAM再执行

硬件连线

Flash Pin MCU--FLash方向 作用
SCK M-->F 串行时钟, 确定Flash工作频率
CS M-->F 片选, 需要交互的时候打开(拉高),用完关闭(拉低)
MOSI M-->F MCU输出/串行输入, 有时候简称SI
MISO M<--F MCU输入/串行输出, 有时候简称SO

此外Flash还有VCC和GND自然不用说, 还有WP(写保护)和 HOLD/RESET(暂停/复位), 这两个一般就拉高处于可写、可用状态, 加起来就8个脚.
还有一种四线SPI的用法加快读的速度(Flash写比较慢也快不了), 叫做QSPI, 此时SI/SO/WP/HOLD都将作为双向IO口与MCU连接. 但多数情况单线就够了.

与Flash的交互通道: SPI的3个寄存器

SPI寄存器 MCU--Flash写入方向 作用
CR M-->F 控制寄存器1~2Byte, 控制Master模式, SPI使能能
DR M<->F 数据寄存器 1Byte, 双向的, 读写都通过这一个. 通常是一串数据包括 1B命令 + 3B地址 + nB数据.
SR M<--F 状态寄存器 1Byte, 读取Flash发来的状态, 主要是看Flash处理完上一条发过去的数据没有

Flash读/擦/写结构

Flash都是必须先擦再写的,否则就写不进去。英文里,为了与普通的写 Write区别, Flash的写叫做Program,所以普通的Write = Erase + Program.
Flash从小到大的结构单位依次是 Page < Sector < Block < Device. Page是Program的最小单位, Sector是Erase的=最小单位. 所以每次写操作是要先在内存中读取并合并至少一个Sector的新旧数据, 擦除并写入的.

最近要搞个新项目, 通过SPI驱动Flash, 芯片是杰理的, 杰理的文档和示例文件都相当于0, 配合的硬件嵌入式工程师说没搞过这块, 就给我连了线, 能读取flash ID就给我了, 也不想搞flash的读写. 他以前倒是搞过, 但是自己写的flash读写代码, 我一看没有1000行也大几百行了. 心里图快, 我实在是不想学习, 于是就想着怎么着去用现成的方案, 调用系统的现成函数, 结果这来来去去搞了一两天, 还是没弄成. 结果李博说flash读写很简单, 一下子就something just clicked for me, 真不如自己操作SPI就写了.
这里面第一个感悟, 就是应该与最原始的东西原汁原味对接, 以为是最麻烦但可能是最节约时间的方式, 原厂做出来也是为了方便用的不是. 算不算是第一性原理?
我发现无论是这次的硬件工程师,还是之前公司配合的硬件工程师, 都喜欢自己写代码和硬件对接. 这次是SPI操作flash,上次是I2C对接触摸芯片. 就是在MCU对接外设这一层级上, 供应链的公司做的都不好, MCU公司给的SDK难用, 缺乏文档, 外设公司的产品不标准, 用MCU公司的SDK接不起来, 出了BUG不能DEBUG, 不如自己看着外设的datasheet自己写代码接, 一次又一次地重复造轮子.这儿就是第二个感悟, MCU与外设对接, 无论是RTOS, SDK, 文档, 接口都缺乏统一标准, 徒增使用门槛, 这也许存在机会,也许是Zephyr的机会. 可惜的是不是国内公司发起的, 可喜的是国内公司在积极参与.

metaso给的回答:

Zephyr OS最初由风河公司(Wind River)开发,并于2016年被Linux基金会接管,成为其管理下的一个开源项目。在项目初期,英特尔、恩智浦半导体公司(NXP)、新思科技(Synopsys)和UbilibiOS Technology Limited等公司是该项目的主要支持者。此外,Linaro也作为白金会员加入了Zephyr项目,为嵌入式和物联网市场提供技术开发和测试的基础。

目前,Zephyr OS由Linux基金会托管,并由一个中立的项目团队维护,这个团队由来自不同公司的开发者和贡献者组成,包括英特尔、恩智浦、正点原子、乐鑫等公司。这些公司通过提供技术支持、代码贡献和资源投入,共同推动了Zephyr OS的发展。

对小孩的感悟: 有用,有趣.

由于打算在特定的杰理MCU中引入第三方的库zlib实现deflate/inflate压缩和解压, 发现比较好的方式是单独选择核心文件进行编译.
zlib官网 https://www.zlib.net/
当前最新的zlib源码 : https://www.zlib.net/zlib-1.3.1.tar.gz
解压缩后, 让cursor生成了一个核心代码的makefile替代原zlib目录下的makefile,使用杰理br25的编译器,自己根据杰理官方的项目中的makefile, 增加了complier flags

TOOL_DIR := C:/JL/pi32/bin
CC    := $(TOOL_DIR)/clang.exe
CXX   := $(TOOL_DIR)/clang.exe
LD    := $(TOOL_DIR)/pi32v2-lto-wrapper.exe
AR    := $(TOOL_DIR)/pi32v2-lto-ar.exe
MKDIR := mkdir_win -p
RM    := rm -rf

# Compiler flags
CFLAGS  = -O2 -Wall -DZ_SOLO \
    -target pi32v2 \
    -mcpu=r3 \
    -integrated-as \
    -flto \
    -Wuninitialized \
    -Wno-invalid-noreturn \
    -fno-common \
    -integrated-as \
    -Oz \
    -g \
    -flto \
    -fallow-pointer-null \
    -fprefer-gnu-section \
    -Wno-shift-negative-value \
    -Wundef \
    -fms-extensions \
    -w \

LDFLAGS =

# Source files
# SRCS = adler32.c compress.c crc32.c deflate.c gzclose.c gzlib.c gzread.c \
#        gzwrite.c infback.c inffast.c inflate.c inftrees.c trees.c uncompr.c zutil.c
SRCS = deflate.c inflate.c zutil.c
# Object files
OBJS = $(SRCS:.c=.o)

# Library name
LIBRARY = libz.a

# Default target
all: $(LIBRARY)

# Rule to build the library
$(LIBRARY): $(OBJS)
    $(AR) rcs $@ $(OBJS)

# Rule to compile source files
%.o: %.c
    $(CC) $(CFLAGS) -c $< -o $@

# Clean target
clean:
    $(RM) $(OBJS) $(LIBRARY)

.PHONY: all clean

zlib目录中运行make, 成功生成libz.a文件.

杰理的官方项目使用Code::Blocks作为编码IDE, 在Code::Blocks项目中添加libz.a: 菜单 > Project > Build Options > Linker Settings > Link Libraries中增加libz.a.
PS: 不放心还可以在other options中增加-LD:\d3\_git\c_proj\SDK_ble\apps\soundbox\zlib

注意, 上面只编译了核心的一些函数, 部分函数如compress/decompress没有. 要检查zlib中有哪些函数: c:\jl\pi32\bin\llvm-nm libz.a
显示如下:

deflate.o:
         U _dist_code
         U _length_code
         U _tr_align
         U _tr_flush_bits
         U _tr_flush_block
         U _tr_init
         U _tr_stored_block
         U adler32
-------- d configuration_table
         U crc32
-------- T deflate
-------- T deflateBound
-------- T deflateCopy
-------- T deflateEnd
-------- T deflateGetDictionary
-------- T deflateInit2_
-------- T deflateInit_
-------- T deflateParams
-------- T deflatePending
-------- T deflatePrime
-------- T deflateReset
-------- T deflateResetKeep
-------- T deflateSetDictionary
-------- T deflateSetHeader
-------- t deflateStateCheck
-------- T deflateTune
-------- D deflate_copyright
-------- t deflate_fast
-------- t deflate_slow
-------- t deflate_stored
-------- t fill_window
-------- t flush_pending
-------- t longest_match
-------- t putShortMSB
-------- t read_buf
-------- t slide_hash
         U z_errmsg
         U zmemcpy
         U zmemzero

inflate.o:
         U adler32
         U crc32
-------- d fixedtables.distfix
-------- d fixedtables.lenfix
-------- T inflate
-------- d inflate.order
-------- T inflateCodesUsed
-------- T inflateCopy
-------- T inflateEnd
-------- T inflateGetDictionary
-------- T inflateGetHeader
-------- T inflateInit2_
-------- T inflateInit_
-------- T inflateMark
-------- T inflatePrime
-------- T inflateReset
-------- T inflateReset2
-------- T inflateResetKeep
-------- T inflateSetDictionary
-------- t inflateStateCheck
-------- T inflateSync
-------- T inflateSyncPoint
-------- T inflateUndermine
-------- T inflateValidate
         U inflate_fast
         U inflate_table
-------- t syncsearch
-------- t updatewindow
         U zmemcpy

zutil.o:
-------- T zError
-------- D z_errmsg
-------- T zlibCompileFlags
-------- T zlibVersion
-------- T zmemcmp
-------- T zmemcpy
-------- T zmemzero

然后在项目的headers中增加zlib.h文件.
示例:


#define CHUNK 16384

int compress_data(const char *src, size_t src_len, unsigned char *dest, size_t *dest_len) {
    int ret;
    z_stream strm;

    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;

    ret = deflateInit(&strm, Z_DEFAULT_COMPRESSION);
    if (ret != Z_OK) return ret;

    strm.avail_in = src_len;
    strm.next_in = (unsigned char *)src;
    strm.avail_out = CHUNK;
    strm.next_out = dest;

    ret = deflate(&strm, Z_FINISH);
    if (ret != Z_STREAM_END) {
        deflateEnd(&strm);
        return ret;
    }

    *dest_len = CHUNK - strm.avail_out;

    deflateEnd(&strm);
    return Z_OK;
}

int decompress_data(const unsigned char *src, size_t src_len, char *dest, size_t *dest_len) {
    int ret;
    z_stream strm;

    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;

    ret = inflateInit(&strm);
    if (ret != Z_OK) return ret;

    strm.avail_in = src_len;
    strm.next_in = (unsigned char *)src;

    strm.avail_out = CHUNK;
    strm.next_out = (unsigned char *)dest;

    ret = inflate(&strm, Z_NO_FLUSH);

    if (ret != Z_STREAM_END) {
        inflateEnd(&strm);
        return ret;
    }

    *dest_len = CHUNK - strm.avail_out;

    inflateEnd(&strm);

    return Z_OK;
}

int test_zlib() {
    const char *original_data = "Hello, World! This is a test of the zlib compression library.";

    size_t original_length = strlen(original_data) + 1; // +1 for null terminator

    unsigned char compressed[CHUNK];

   // Compress the data
   size_t compressed_length;
   if(compress_data(original_data, original_length, compressed, &compressed_length) != Z_OK){
       printf("Failed to compress data\n");
       return 1;
   }

   printf("Original length: %zu\n", original_length);
   printf("Compressed length: %zu\n", compressed_length);

   // Decompress the data
   char decompressed[CHUNK];
   size_t decompressed_length;
   if(decompress_data(compressed, compressed_length, decompressed, &decompressed_length) != Z_OK){
       printf("Failed to decompress data\n");
       return 1;
   }

   printf("Decompressed length: %zu\n", decompressed_length);
   printf("Decompressed data: %s\n", decompressed);


   return 0;
}

在主函数中引用test_zlib()就可以编译了. 实测编译通过.

信息来源: 广东政务服务网(也是申请平台)
采集日期: 2024/12/26

创业类补贴(国家标准名:创业补贴申领)

一次性创业资助申领

补贴条件:1.初创企业的法定代表人或经营者(女性不超过55周岁、男性不超过60周岁)符合以下条件之一:
(1)普通高等学校、中等职业学校、技工院校学生(在校及毕业5年内)和毕业5年内的出国(境)留学回国人员;
(2)军转干部、退役军人;
(3)登记失业人员、就业困难人员、本省脱贫人口;
(4)返乡创业人员,具体包括:
第一类:户籍地为广州、深圳、珠海、佛山、东莞、中山市,离开户籍所在地市外出求学(指在普通高等学校、中等职业学校、技工院校求学,下同)、务工后返回原户籍地所辖乡镇(行政区域中无乡镇的可适当调整)创业的劳动者(以营业执照所载地址为准);
第二类:在第一项列举地区以外市所辖乡镇创业(不含创办个体工商户)的各类劳动者(有关地市可根据地方经济发展水平、资金承受能力等情况,自行确定是否将县城镇、中心镇除外);
第三类:户籍地为第一项列举地区以外市,离开户籍所在地市外出求学、务工后返回原户籍地市辖区内创业的劳动者;
(5)创办驿道客栈、民宿、农家乐的人员。
2.初创企业登记注册满6个月,申请补贴前连续3个月有在职员工(不含法定代表人或经营者)正常缴纳社会保险费,且申请时未被市场监管部门列入“经营异常名录”。
补贴对象:符合条件的创业者。符合条件人员和创办主体只能享受一次创业资助。
补贴标准:10000元。
补贴期限:一次性。

创业带动就业补贴申领(国家标准名:创业补贴申领)

补贴条件:1.初创企业招用员工(签订一年以上期限劳动合同、申请补贴前连续6个月为招用员工缴纳社会保险费且申请补贴时仍在本企业就业,法定代表人或个体户经营者除外)。2.初创企业吸纳劳动者就业申请补贴后12个月内,不同初创企业吸纳同一劳动者就业的不能再次申领补贴。
补贴对象:符合条件的用人单位(所有股东均为法人股东的企业、劳务派遣企业除外)。同一法定代表人名下有多家初创企业的,只有一家可申请创业带动就业补贴。
补贴标准:招用3人以下的按每人2000元给予补贴;招用4人以上的每增加1人给予3000元补贴,总额最高不超过3万元。
首次补贴申请应于相关创业主体登记注册之日起3年内提出,最后一次申请时间不得超过登记注册之日起4年。

创业租金补贴申领(国家标准名:创业补贴申领)

受理条件

补贴条件:1.初创企业的法定代表人或经营者(女性不超过55周岁、男性不超过60周岁)符合以下条件之一:
(1)普通高等学校、中等职业学校、技工院校学生(在校及毕业5年内)和毕业5年内的出国(境)留学回国人员;
(2)军转干部、退役军人;
(3)登记失业人员、就业困难人员、本省脱贫人口;
(4)创办驿道客栈、民宿、农家乐的人员。
2.初创企业租赁场地用于经营(租赁地址与注册登记地一致),相关场地非法定代表人或经营者自有物业。
3.初创企业申请补贴前连续3个月有在职员工(不含法定代表人或经营者)正常缴纳社会保险费,且申请时未被市场监管部门列入“经营异常名录”。
补贴对象:符合条件的创业者。
补贴标准:珠三角地区每年最高6000元、其他地区每年最高4000元。
补贴期限:累计不超过3年。

6000补三年即500每月12月3年=18000元.

创业孵化补贴申领 (国家标准名:创业补贴申领)

补贴条件:1.县级以上人力资源社会保障部门认定的创业孵化基地为普通高等学校、中等职业学校、技工院校学生(在校及毕业5年内)、毕业5年内的出国(境)留学回国人员、港澳台青年、就业困难人员、返乡创业人员、退役军人等六类创业者提供1年以上的创业孵化服务并孵化成功(入孵团队在孵化期内登记注册,六类创业者为法定代表人)。2.入孵创业实体的营业执照地址在基地地址范围内,申请时未被市场监管部门列入“经营异常名录”。3.同一创业者有多家创业实体入驻创业孵化基地的,只有一家企业符合补贴条件。
补贴对象:符合条件的创业孵化基地运营主体或主办单位。
补贴标准:按每年每户3000元标准给予补贴。
补贴期限:从登记注册之日起算,最长不超过2年。

这个只针对孵化器

创业培训补贴申领 (无国家标准名)

补贴条件:1.创业培训定点机构(或特色创业实训承办机构)为有创业要求和培训愿望并具备一定创业条件的城乡劳动者(含普通高等学校、中等职业院校、技工院校在校生)提供免费创业培训。2.相关人员参加创业培训后取得创业培训(实训)合格证书。
补贴对象:符合条件的培训机构。
补贴标准:1.创办企业培训(GYB+SYB,共80学时)每人最高可补贴1500元。2.网络创业培训每人最高可补贴2000元。3.特色创业实训每人最高可补贴2800元。
补贴期限:符合条件的人员每种类型只能享受一次创业培训补贴,每年最多享受一种类型。
申请程序:创业培训机构应于证书核发之日起12个月内向培训备案所在地人力资源社会保障部门提出申请。

小型微型企业银行贷款担保费补贴项目

1.在深圳市内依法经营,具有独立法人资格的企业;
2.守法经营,管理规范,无国家、省、市有关失信惩戒措施清单规定可限制申请财政性资金项目的情形,包括但不限于依法依规被列入严重失信主体名单,未重复申报项目;
3.申报的项目符合国家产业政策和地方经济社会发展要求,不属于政府投资建设项目;
4.申报单位符合国家有关小型、微型企业划型标准;
5.通过融资性担保机构担保获得单笔在1000万元及以下的银行贷款,且实际发生该笔银行贷款的担保费用。

企业其他补贴

吸纳脱贫人口社保补贴和岗位补贴

(一)用人单位招用本省以及对口协作地区(广西壮族自治区、贵州省、西藏自治区、新疆维吾尔自治区、云南省昭通市、江西省赣州市、重庆市巫山县,对口协作地区另有调整的,从其规定)的脱贫人口,签订一年以上劳动合同。
(二)用人单位为招用人员连续正常缴纳社会保险费3个月以上,且当前参保状态正常。

小微企业社保补贴申领(国家标准名:高校毕业生社保补贴申领)

1.用人单位属于小型微型企业。2.用人单位招用毕业2年内高校毕业生,与其签订一年以上劳动合同。3.相关人员按规定缴纳社会保险费。

(八)鼓励吸纳青年就业。对2023年1月1日后招用毕业年度及离校2年内未就业高校毕业生、登
记失业的16至24岁青年,签订劳动合同并为其缴纳失业、工伤、企业职工养老保险费1个月以上
的企业,按每招用1人1000元的标准给予一次性吸纳就业补贴或一次性扩岗补助,政策实施期限
截至2023年12月31日。对见习期未满与见习人员签订劳动合同的用人单位,给予剩余期限见习补
贴,政策实施期限截至2023年12月31日。高校毕业生基层就业补贴,按规定不再执行。自2024
年1月1日起,提高小微企业社保补贴标准,按用人单位为符合条件人员实际缴纳社会保险费给予
补贴;符合条件的用人单位,组织毕业2年内高校毕业生和登记失业的16至24岁青年参加就业见
习,并按不低于我市最低工资标准的80%对见习人员支付工作补贴的,按每人每月我市最低工资
标准且不高于用人单位实际支付的工作补贴金额向用人单位给予见习补贴;市外“双高计划”学生顶
岗实习补助不再执行。(责任单位:市人力资源保障局、市教育局、市财政局,各区政府)

好久没有写过这种给自己"入门"的文章了. 不过最近看一篇文章强推Typescript, 还把js比作汇编, ts比作高级语言, 说你看现在还有几个人用汇编, 以后大家一样都是用ts的, 强推味道太重, 不过下载cocos creator, 也已经把ts作为默认语言了, 另外小程序也支持ts(似乎需要特殊设置一下,默认还是js), 再加上最近几年ts在语言排行榜上爬升很快, 看来不得不了解了.
参考教程:https://www.runoob.com/typescript/ts-features.html
在线playground: https://www.typescriptlang.org/play

安装

npm i -g typescript 即可, 安装后tsc可以运行就说明安装成功.

编译

tsc file.ts即可编译成file.js
在项目中, 可以先初始化文件夹tsc --init, 然后修改tsconfig.json,将"outDir": "./build",, 这样只运行tsc可以自动编译到build目录中.

REPL

由于运行tsc是用来编译的, REPL需要安装npm i -g ts-node, 然后运行ts-node即可.

类型定义: 变量后 : 类型名

如果:any则和js一样不限制类型.

  • 函数形参: 必须定义类型
  • let/const 变量: 可以不定义, 自动取初始化类型. 如果不初始化, 则类型为any
  • 对象成员: 可以不定义, 自动取初始化类型. 因为这个过于灵活, 所以有了interface关键词, 专门用来定义class的类型.

新关键字 interface implements

定义class需要遵从的形式

interface Person {
  name: string;
  age: number;
  greet(): void;
}

class Student implements Person {
  constructor(public name: string, public age: number) {}

  greet() {
    console.log(`Hello, my name is ${this.name}`);
  }
}

新关键字 type

定义新类型

type StringOrNumber = string | number;
let value: StringOrNumber = 42;

新关键词 as

因为js的不同类型有不同的方法, 有时候ts无法判断any类型,也就不知道这个变量有没有对应方法, 这时候就要用as来强制转换类型,以便访问该类型的方法

let value: any = "hello";
let strLength: number = (value as string).length;

新关键字 public private protected

定义对象成员的访问权限

新关键字 enum

定义枚举类型. 注意enum的定义方式比较像C语言, 没有赋值等号.

enum Direction {
  Up,
  Down,
  Left,
  Right,
}
let dir: Direction = Direction.Up;

很有意思的是Direction定义后, 在js中看起来是这样的

var Direction;
(function (Direction) {
    Direction[Direction["Up"] = 0] = "Up";
    Direction[Direction["Down"] = 1] = "Down";
    Direction[Direction["Left"] = 2] = "Left";
    Direction[Direction["Right"] = 3] = "Right";
})(Direction || (Direction = {}));

console.log

{
  '0': 'Up',
  '1': 'Down',
  '2': 'Left',
  '3': 'Right',
  Up: 0,
  Down: 1,
  Left: 2,
  Right: 3
}

貌似在新的浏览器和node(v20)中, enum都已经作为保留关键字了, 但还不能使用.

新关键词 abstract

与class的区别就是不能被实例化.

新类型 any

表示任何类型

新类型 unknown

与 any 类似,但更严格。必须经过类型检查后才能赋值给其他类型变量。

let value: unknown = "Hello";
if (typeof value === "string") {
  let message: string = value;
}

新类型 元组 tuples

这不是一个关键字, 而是允许定义具有固定数量和类型的数组

let point: [number, number] = [10, 20];

新类型 泛型 Generics

用尖括号<T>定义, 相当于T是可变化的类型(可以认为类型成了变量了), 在使用函数的时候再去定义类型.

function identity<T>(value: T): T {
  return value;
}

let num = identity<number>(42);

新类型 voidnever

void类型用于表示函数没有返回值,但可以返回undefined或null,并且函数可以正常执行并完成操作。
never类型用于表示函数永远不会返回任何值,通常是因为函数会抛出异常或进入无限循环。

function error(): never { throw new Error("error"); }

联合类型

用或|表示类型可以是几种之一

let id: string | number;
id = "123";
id = 456;

字面量类型

字面量类型可以让变量只能拥有特定的值,用于结合联合类型定义变量的特定状态。

let direction: "up" | "down" | "left" | "right";
direction = "up";

新运算符???

TypeScript 增加了 JavaScript 的可选链 (?.) 和空值合并运算符 (??),简化了代码中对可能为 null 或 undefined 值的处理。


let user = { name: "Alice", address: { city: "Wonderland" } };
console.log(user?.address?.city); // 如果 address 存在则输出 city,否则返回 undefined

let value = null;
console.log(value ?? "default"); // 如果 value 为 null 或 undefined,则返回 "default"
``
`?`确实简化了很多操作, 否则深度访问一个不存在的key, js就会报错.
`??`和`||`还是有区别的, `??`只判断null和undefined, 而`||`还会判断false, 0, 空字符串'', NaN.

  1. 美洲: 除了北美的美加两国说英语, 巴西说葡萄牙语外, 其他各个国家几乎都说西班牙语.
  2. 东南亚: 几乎各个国家都说各自的语言. 少数国家如新加坡, 菲律宾还使用英语. 当然新加坡通行4种语言,还包括华语,马来语和3. 泰米尔语. 另外老挝,缅甸,泰国本族语言是汉藏语系的衍生, 跟我国壮族,侗族,傣族等语言比较接近.
  3. 中亚: 中亚五国虽然都有自已的语言, 但由于苏联时代的影响, 俄语比较通用.
  4. 中东: 阿拉伯语比较通用. 少数不同是以色列说希伯来语, 伊朗说波斯语, 阿富汗说普什图语和达里语.
  5. 澳洲: 主要通行英语.
  6. 非洲: 几大殖民势力的语言都有通用.
  • 英语: 尼日利亚、加纳、利比里亚、塞拉利昂、冈比亚、肯尼亚、坦桑尼亚、马拉维、纳米比亚、博茨瓦纳、南非、斯威士兰、津巴布韦、赞比亚等国家将英语作为官方语言,
  • 法语: 包括刚果(金)、刚果(布)、科特迪瓦、卢旺达、中非共和国、多哥、几内亚、马里、布基纳法索、喀麦隆、乍得、科摩罗、吉布提、塞内加尔、马达加斯加、毛里塔尼亚、阿尔及利亚、摩洛哥、塞舌尔等
  • 葡萄牙语: 葡萄牙语是安哥拉、莫桑比克、圣多美和普林西比等国家的官方语言
  • 阿拉伯语: 在北非和部分东非国家广泛使用,是埃及、苏丹、利比亚、突尼斯、阿尔及利亚、摩洛哥、索马里、毛里塔尼亚、吉布提、科摩罗和乍得的官方语言

根据metaso AI的总结, 主要小语种在中国开设专业的大学数量:
俄语:174至181所大学
西班牙语:超过100所大学(具体数字在不同证据中有所不同)
阿拉伯语:41至10所大学(数据不一致)
法语:148至71所大学(数据不一致)
葡萄牙语:39至6所大学(数据不一致)

如果要与海外做生意, EF有一个英语熟练度指标,每年都会发布,而且还分别做中文和英文版本. https://www.ef.com.cn/epi/
2023年英文版: https://www.ef.com/assetscdn/WIBIwq6RdJvcD9bc8RMd/cefcom-epi-site/reports/2023/ef-epi-2023-english.pdf
2024年中文版: https://www.ef.com/assetscdn/WIBIwq6RdJvcD9bc8RMd/cefcom-epi-site/reports/2024/ef-epi-2024-simplified-chinese.pdf
可以看出, 除了英语母语国家, 拉美虽然说西班牙语, 但英语水平也是不赖的. 欧洲也是如此. 甚至在西班牙和葡萄牙都有不错的成绩. 但是在中东, 中亚, 南亚, 以及非洲的非英语国家, 英语熟练度就比较差了. 很奇怪的是英语国家印度的德里竟然评价为极不熟练.
EF的这个指标主要是通过在线自愿测试得出, 且年龄中位数为25岁.

想做像素动画,例如64x20px, 该怎么做?
尝试了几种思路

用视频编辑软件,可以自定义分辨率为64x20

PPT + Gif编辑

  • ScreenToGif (简称S2G)可以录制gif, 导出gif也能导出视频.
    这样用Powerpoint做动画,S2G录制. PPT上尺寸大一些, 录制的动图可以在缩小为需要的大小.

游戏的PNG Spritesheet技术

游戏一般把精灵角色的多个动作合并到一张PNG中, 这样加载起来更快. 这个想法最适合我.

打算用微信小程序将数据存为UTF-8格式的CSV,让Excel编辑.
使用wx.writeFile或者writeFileSync可以设置编码为UTF-8保存. 但此后的坑就连续不断出现了.
通过shareFileMessage转给自己, 用Excel打开, 就会发现是乱码. 原因是Excel只支持带BOM的UTF-8. 开始解决这个问题, 然而微信和Excel都有坑, 分别说下:

微信的系统差异

要给文件前面加UTF-8 BOM, 最简单是在保存的字符串前加入 \ufeff 再用writeFile+UTF8格式保存. 你会发现Android版本微信很好地完成了这个任务, Excel顺利打开, 然而ios版本微信会把你加入的\ufeff自动删除! 保存了个寂寞

微信用binary方式保存

问遍教程,都会让你用Buffer和TextEncoder通过UTF8编码转为ArrayBuffer前面再加入BOM头0xEF、0xBB、0xBF, 但是微信小程序不支持这两个常见的类Buffer和TextEncoder. 除非你自己实现一个.

微信曲线救国方式

碰到ios, 先保存,再读取,再在前面加入BOM头,再保存. 利用微信writeFile保存功能支持UTF8来解决

    tableStr = '\ufeff' + tableStr // 增加UTF8 BOM头
    const fs = wx.getFileSystemManager()
    fs.writeFileSync(filename, tableStr, 'utf-8')
    const deviceInfo = wx.getDeviceInfo()
    if(deviceInfo.platform == 'ios'){
      // 由于iOS系统上会把utf8保存的文件的前面的bom头删除(android不会),所以需要以arrayBuffer的方式读入文件之后重新加上utf8 BOM头。
      // 之所以不在内存中完成转换,而是通过文件读写的方式转换, 原因是内存中转换字符串到Utf8的两种手段Buffer/TextEncoder在微信小程序中都不支持。
      let file = fs.readFileSync(filename) 
      const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
      // 将文件内容转换为 Uint8Array 并合并
      const contentArray = new Uint8Array(file);
      const mergedArray = new Uint8Array(bom.length + contentArray.length);
      mergedArray.set(bom, 0);
      mergedArray.set(contentArray, bom.length);
      fs.writeFileSync(filename, mergedArray.buffer, 'binary')
    }

Excel的坑: 从2016版本才开始支持CSV UTF-8格式

如果你是2016以前的版本就不要挣扎了, 还不如用Win10/11上的记事本编辑了.

人也浪漫,字也浪漫,玉树银花自凋零。
来也如风,去也如风,犹记桃花笑盈盈。
弱水三千饮一瓢,我自逍遥。
莫为我死悲寂寥,翩然舞蹈。
-- 2024/12/4 纪念琼瑶去世

我感觉是不能着急,陷入要么全部让AI完成,要么完全不信任AI代码的极端。
程序员做的工作应该转向需求分析、概要设计、详细设计这些工作,将框架内的编码和单元测试留给AI来做。

C

一开始的简单任务, 都可以作对, 但是一旦开始出错, 如编译错误, 往往比较难改对.
最好一开始就用git, 修改正确后就立刻commit, 否则成果容易毁于一句话.
composer开新的会话要小心, 似乎新会话像一个新程序员, 跟旧的会话风格大不一样, 还可能大幅修改已经完善正确的代码
cursor写一个函数或一个文件中的几个函数是相对安全的, 整个项目大幅修改文件, 往往陷入编译错误数个回合不能自拔

在以下情况出过错, 加入.cursorrules看能否防止他再次出错

  • 在 Makefile 中,条件语句不能放在规则内部。
  • 请尤其注意函数先后的声明顺序,以及函数调用的顺序。
  • for循环的条件判断如果是变量x>0,并且x在每个循环中递减时, x的类型不能为unsigned, 否则不能退出循环.

B站上看到这么个视频https://www.bilibili.com/video/BV1H14y1p72L/
了解到还有这么一种玩法.大概意思是在电脑上通过docker开android虚拟机, 然后手机远程连接, 就像换了个手机一样.
基于视频的说法, 步骤是:

电脑端 手机端
容器 docker
虚拟机 redroid
私网 Zerotier
远程屏幕控制 ScrCpy

如果都在内网似乎Zerotier就不需要了.
另外虚拟机还可以开在云电脑或服务器上, 应该也不需要Zerotier.
感觉还有简单的方式, 就是在虚拟机中安装向日葵来远程控制. 只不过向日葵安装在虚拟机, 有可能会受限于虚拟机权限, 而ScrCpy安装在宿主机, 理论上不受虚拟机权限限制.

市监局 https://amr.sz.gov.cn/
房屋编码查询 https://tybm.szzlb.gov.cn:10000/AddressWeb/#/
经营范围查询 https://www.jyfwyun.com/home

如果注册选择秒批, 在选择经营范围的时候, 只有150个可选, 而实际上经营范围有1000~2000个.而且这一步比较靠后, 可能填了很多内容才出现经营范围选不了. 这时候只能删掉重选了.

秒批和正常注册流程有什么不同?

正常注册相对于秒批:

  1. 除了选择公司, 还能选择医疗或者其他要前置审批或特殊审批的企业.
  2. 公司名称里的行业用语可选项更多.
  3. 企业组织形式不限于内资有限公司.
  4. 股东不限于自然人
  5. 经营范围完整. 秒批只有完整范围的5%.

我的iqoo neo5又给摔了。 OLed屏幕不出意料的开始传染。因为第1次屏幕是我自己换的,结果到了vivo的门店里不保修了。工作人员说必须要原装屏幕才能享受折扣价450块钱换屏幕,否则这里850块钱还不如买新机了。
我看了一下二手机还没有换屏幕贵才六百多。
没办法,只好自己再买一个第三方的。上次买第3方的屏幕花了300多,当时就想不如换官方的屏幕。但是看到官方屏幕的价格是在我换屏幕之后。上次的第3方的屏幕有几个问题,一个就是显示区域小,第2个就是不支持指纹。
这次在淘宝上重新买了新的屏幕,价格260,据说支持指纹。这个屏幕带框架拆下来挺麻烦的,把所有的元器件全部拆光了,换到新的屏幕框架上。装完发现这个屏幕比第1次买的第3方屏还要小。第1次买的屏幕至少前摄像头是一个圆孔,这次直接变成了水滴屏。
测试完倒是确实支持指纹的。多点心理安慰。
在等屏幕的期间,我找备用机发现几乎所有的我用过的手机都被我屏幕摔碎了。看来屏幕在我手里摔碎是必然的。只是以前的屏幕都是lcd屏,摔碎了之后不会导致传染。
我找了一下现在比较强的lcd屏,发现iqoo z8是LCD最强的手机了,支持联发科8200,性能超出骁龙888。最大12gb+512gb。价格在1000~1200之间。
我看iqoo Z系列现在还在出新的lcd屏的手机,最新的z9用的是骁龙6系列的cpu,性能还不如z8。