
简介九齐NY8系列单片机全型号C语言与汇编例程合集主要面向使用九齐NY8A/NY8B/NY8T等芯片的嵌入式开发者和单片机学习者可帮助解决多型号代码分散、外设驱动参考资料难找的问题。包内共112个文件以.h头文件、C/汇编源程序、工程文件nysln、cb、naprj为主并附带说明文档与版本记录压缩包仅335KB便于快速下载和整理。目前已有50人学习。例程按芯片型号分层组织覆盖NY8A051D、NY8B062D等数十款主流型号每个型号均提供标准C语言与传统汇编两种实现适合不同开发习惯的读者对照使用。内容涉及初始化、GPIO控制、定时器、PWM、ADC、UART、I2C、SPI等常用外设驱动示例配有头文件与宏定义可直接嵌入项目或作为二次开发模板能显著缩短前期移植和调试时间。 如果你做过小家电、玩具或者消费类电子方案对九齐PADAUKNY8系列单片机一定不陌生。这个系列以OTP形式出货、价格便宜、供货稳定在很多成本敏感的产品里出现率极高。但真正上手又会发现一个尴尬的问题官方资料和例程都比较零散想找一套能直接“抄作业”的C语言与汇编例程往往要翻遍论坛、群里求人。这个合集就是把NY8A、NY8B、NY8T这几个主流分支的常见外设例程全部整理到一起编译环境、代码风格、IO映射都做了统一适合从51/STM32转过来的工程师也适合刚接触九齐的初学者。下面我讲一下做这套例程时的设计思路和踩坑记录希望能给你省点时间。1. 为什么做这个合集NY8系列的痛点与选型思路1.1 NY8A、NY8B、NY8T到底怎么选九齐NY8系列虽然型号后缀看着复杂但核心其实就三大类NY8A是通用IO型适合做灯控、玩具、逻辑控制这类纯数字应用NY8B在IO基础上加了ADC等模拟外设适合需要采集电压电流、做电池电量检测的产品NY8T则内置触摸检测前端专门做触摸按键和触控面板。这三类共用同一套内核指令集只是外设资源、封装和引脚数不同所以例程库按“基础模块”和“增强模块”两层来组织基础模块覆盖GPIO、定时器、中断、PWM、看门狗所有型号通用增强模块对应ADC和触摸再按型号拆分支。选型时建议先列需求清单需要几个IO、有没有模拟量采集、要不要触摸、成本预算多少。比如一个普通LED夜灯NY8A系列就够如果是带电池电量显示的电子烟或者小风扇就要考虑NY8B如果产品面板上有三四个触摸按键直接看NY8T别用一个通用MCU去软件模拟触摸抗干扰和灵敏度都会让你头疼。1.2 先说痛点再谈方案最大的痛点是资料分散。九齐官方IDE里自带几个示例工程但表达方式非常“原厂”注释少、结构乱而且偏汇编。国内群和论坛里流传的代码往往只针对某一颗料换型号就要从头改配置。另外很多从51转过来的工程师会习惯性用delay去写按键、LED扫描在NY8这种资源紧张、OTP不可擦除的芯片上很容易翻车。我在整理例程合集前先做了一份资源对照表把常用型号的ROM大小、RAM大小、定时器个数、有没有ADC、有没有触摸模块列出来贴在工程根目录下。这一步强烈建议你也做因为很多报错根本原因是“这颗料没有那个外设”而不是代码本身写错了。例程合集的意义不是替代数据手册而是帮你快速确认“这颗料能干什么、代码该怎么开头”。1.3 例程目录与代码规范合集的目录按外设模块划分每个模块下放C版和汇编版两个工程。目录结构大概是这样的ny8_demo/ ├── 00_Template/ # 最小工程模板C版和ASM版 ├── 01_GPIO_LED/ # 点亮LED、IO翻转 ├── 02_Key_Scan/ # 按键扫描、软件去抖 ├── 03_Timer/ # T16/T2/T3定时中断 ├── 04_PWM_Buzzer/ # PWM蜂鸣器、软件PWM ├── 05_ADC/ # NY8B系列ADC采集 ├── 06_Touch_Key/ # NY8T系列触摸按键 ├── 07_LowPower_WDT/ # 休眠、唤醒、看门狗 ├── 08_Mix_C_Asm/ # C与汇编混编示例 └── common/ ├── ny8_config.h # 型号宏定义、IO映射 └── delay.c/h # 软件延时C和ASM版本所有例程统一用一个ny8_config.h做IO映射。比如LED接到了PA0那就定义#define LED_IO PA0业务代码里只操作LED_IO移植到别的板子时只需要改这个头文件。这个习惯非常重要九齐不同型号的IO寄存器名字基本一致但封装和引脚功能差异很大不改映射就移植代码烧进去大概率是灯的引脚不对、按键不灵敏这种诡异问题。2. 开发环境与工程模板先把地基打好2.1 PADAUK IDE与PDS编译器九齐的官方IDE名称就叫PADAUK IDE下载后安装里面会自带PDS编译器。PDS支持C语言和汇编混合编程不过这家的C语言和标准C有差异没有标准库函数绝大多数型号也没有硬件串口printf这种调试手段基本别指望。我第一次用的时候甚至找不到main函数必须怎么写翻了一遍官方示例才明白入口就是普通main()但中断、IO配置这类都要调用编译器内建的伪指令或库函数。初次使用建议先摸清楚三个地方的配置Option里的芯片型号选择决定编译器按哪颗料的资源分配ROM/RAM时钟源选择常见有内部高速RCIHRC、内部低速RCILRC、外部晶振EOSC后面算延时和PWM频率全靠它看门狗WDT开关和溢出时间默认可能开着如果程序里没喂狗跑几分钟就复位你还不一定查得出来。这套环境整体风格偏老派没有STM32CubeMX那种图形化配置但胜在编译快、生成代码小。对资源本来就紧张的OTP芯片来说这是实打实的优势。2.2 最小工程模板C版点灯对照汇编版不管多么复杂的项目第一步永远是点灯。C版最小模板里延时函数用软件空循环实现核心代码如下#include NY8.h // 具体头文件名以IDE版本为准 void delay_loops(unsigned int cnt) { while (cnt--); } void main(void) { PAC0 | 0x01; // 设置PA0为输出 PA0 0; // 初始低电平LED亮 while (1) { PA0 ~PA0; // 翻转IO delay_loops(30000); } }这里有个关键点PAC0是方向控制寄存器置1对应的引脚才是输出。很多从51转过来的人习惯先写引脚数据寄存器在这里必然翻车——引脚方向没配好PA00写进去毫无反应LED死活不亮。而汇编版点灯能让你更直观看到底层操作; 汇编版点灯示意具体指令以官方Instruction Set为准 MOVIA 0x01 MOV PAC0, A ; PA0配置为输出 Loop: MOVIA 0x01 XOR PA, A ; PA0翻转 CALL Delay GOTO Loop建议C版和汇编版对照着看C版里的PAC0 | 0x01本质就是一次读-改-写操作汇编版则是先加载值然后移动到方向寄存器。这个对应关系建立起来之后你再去看数据手册的寄存器说明会轻松非常多。2.3 C与汇编混合编程的两种实用姿势NY8系列的C编译器做得已经不错但有些场合还是必须碰汇编比如做精确到指令周期的延时、操作某些特殊寄存器或者ROM剩最后几十条指令塞不下C代码时。合集中专门放了一个08_Mix_C_Asm的目录里面提供了两种混编方式。第一种是内联汇编直接在C函数里嵌入汇编片段。PDS编译器的语法大致是void inline_asm_demo(void) { __asm ; 汇编指令写在这里 NOP __endasm }第二种是写一个独立的汇编函数在C里用extern声明后直接调用。这种方式比较适合做延时、驱动WS2812这类对时序极端敏感的模块。但要注意用C调用汇编函数时参数传递、寄存器保存和恢复的约定要跟编译器对齐否则轻则传参出错重则栈被打乱。我遇到过一次非常隐蔽的bug汇编函数里用了某个通用寄存器没有保存原值返回后C代码里一个循环变量被冲掉了程序行为变得完全随机查了很久才发现是寄存器现场没保护。3. 核心外设例程实现细节3.1 GPIO控制与按键扫描别用delay硬等NY8的GPIO实战中最常见的坑就是按键扫描。很多初学者习惯这样写检测到按键按下delay_loops抖一下再检测一次。这在主循环只有点灯任务的demo里没问题一旦产品里同时有数码管动态扫描、蜂鸣器鸣叫delay会把整个系统的实时性拖垮。按键扫描的正确做法是定时中断里分时处理。合集里我放了一个典型的10ms扫描例子思路是用定时器产生1ms中断每10次中断做一次按键采样连续两次采样电平一致才认为有效。这样既完成了去抖又不会阻塞主循环。核心代码如下unsigned char key_state 0; unsigned char key_tick 0; void timer1ms_isr(void) // 1ms定时中断回调 { key_tick; if (key_tick 10) { key_tick 0; unsigned char level (PA 0x02) ? 1 : 0; // 读取PA1 if (level key_state) { // 两次采样一致按键有效 } else { key_state level; } } }再补一句按键按下和松开分别做短按、长按、双击判定时千万别在中断里跑复杂逻辑把标志位置好主循环里再处理业务。3.2 定时器与中断1ms时基到底怎么搭NY8系列常见的定时器有T16、T2、T3不同型号资源不一样T16一般是16位T2/T3是8位。搭时基的关键是要算清楚分频系数和装载值。以内部高速RC 4MHz为例要得到1ms中断假设定时器时钟等于系统时钟那么1ms需要4000个周期。16位定时器可以容纳这个数但8位定时器最大只能计到255必须插分频。计算方法非常直观定时周期 分频系数 × (定时器最大计数值 - 装载值 1) / 定时器时钟频率如果选8位定时器分频1:64那么装载值算出来约等于256 - 4000 / 64 ≈ 256 - 62 194。也就是说每次溢出中断前要重装初值194。这里有个容易忽略的点8位定时器的重装过程在汇编层面通常是“先关中断再写寄存器再开中断”防止写入一半的时候定时器溢出导致差一个数。C编译器不一定自动帮你处理最好自己用内联汇编或者关中断语句包一下。3.3 PWM与蜂鸣器驱动软件PWM怎么算NY8的部分型号有硬件PWM/蜂鸣器驱动模块没有的型号就只能用定时器中断做软件PWM。软件PWM的原理是用定时中断维持一个时基计数器比如频率4kHz周期250us中断里给PWM周期计数器累加再跟占空比阈值比较决定IO输出高还是低。算占空比的过程很简单假设要50%占空比高电平时间就是125us250us周期剩下125us输出低电平。驱动蜂鸣器时实测下来频率2.7kHz左右的方波发声效果在小尺寸蜂鸣器上比较明显你可以把例程的PWM频率参数直接改成2700听一下效果再微调。驱动电机时软件PWM占空比对应速度但要注意NY8输出电流有限别直接推电机需要通过MOS管或驱动芯片栅极串一个100到200欧电阻能减小开关噪声。这也就是网上经常搜到的“单片机控制MOS管电路图”的核心场景。3.4 ADC采集与触摸按键NY8B和NY8T的典型用法NY8B系列带ADC做电池电量检测时有个常见需求用电阻分压把电池电压降到ADC量程内然后软件里换算回来。例程里我写了两种读取方式查询方式和定时采集方式。查询方式简单配置ADC、启动转换、等待标志位、读结果定时采集方式适合需要持续显示电量的产品建议每200ms采样一次连续取4次做平均滤波。ADC采集还有一个很实用的技巧在转换结果上加一个简单的软件平均值滤波比如滑动平均窗口4能有效抑制工频干扰和噪声。代码逻辑很简单维护一个长度为4的数组每次采样后求算术平均。代价是RAM占用多一点但NY8B系列RAM相对宽裕这点开销值得。NY8T的触摸按键例程和普通MCU做电容触摸的原理类似是通过检测触摸感应模块的电容变化来判断有没有手指靠近。调试触摸的坑主要在环境变化湿度、温度、覆盖面板材质都会影响基础电容值。量产前一定要做温湿度环境测试不能在自己桌上调好就发出去。3.5 低功耗与看门狗OTP芯片的保命手段NY8系列支持休眠指令C和汇编都有对应写法。休眠前把不需要的外设关掉、IO设置成确定电平避免悬空导致漏电然后执行休眠指令。实测下来正常休眠功耗可以做到很低但前提是外部电路不能偷偷耗电。有一次我做一个遥控器方案MCU休眠电流只有1uA不到整机却有0.8mA排查了半天才发现是LED限流电阻接错位置引脚高电平时一直经过电阻耗电。这类问题例程帮不了你只能靠万用表逐段排查。看门狗的设置建议在工程Option里就配好如果程序运行时间较长最好用定时中断对“喂狗”做节拍控制。但注意不要在中断服务函数里喂狗然后主循环跑飞狗照样不叫——写业务代码时喂狗点要放在主循环的关键位置确认核心业务确实还在跑。4. 实操过程从空工程到点亮一颗LED4.1 建工程、选芯片、配时钟我以NY8A051F这颗料为例完整走一遍流程。打开PADAUK IDE新建工程在Option里选择芯片型号搜索051F就能找到。时钟源选IHRC频率设置为4MHz。WDT暂时关闭先保证程序能稳定跑起来。工程创建好后IDE会自动生成一个带main函数的C文件模板和一个头文件引用。然后打开ny8_config.h把LED引脚宏配置好#define LED_PORT PA #define LED_PIN 0 #define LED_ON() (LED_PORT ~(1 LED_PIN)) #define LED_OFF() (LED_PORT | (1 LED_PIN))写完点灯代码点击编译几秒钟后输出窗口会显示ROM/RAM占用情况。如果编译通过在工程目录下能找到生成的可烧录文件一般是.bin或者.hex格式。4.2 烧录、验证与OTP的“后悔药”九齐官方烧录工具一般是仿真烧录一体机连接方式很简单接线照着烧录器说明书来VDD、GND、DAT、CLK这几个信号。打开烧录软件加载编译产物点击烧录前先把芯片插到烧录座里。这里我要重点说一句OTP芯片烧录是不可逆的程序有bug、参数配错芯片就废了。我刚开始烧废过好几片后来总结出一个习惯——烧录前在代码里加一个自检动作上电后LED先慢闪三下再进入业务逻辑。这能让你烧完立刻知道程序有没有正确启动不用接仿真器盯着看。如果烧录软件提示校验失败先检查芯片是否放反、引脚是否接触良好、供电电压是否稳定。烧录器接触不良是最常见的原因多拔插几次、用酒精棉擦一下座子的弹片大概率能解决。4.3 例程从一颗料移植到另一颗料合集的例程不是写完就完事更重要的是快速移植。假设我在NY8A051F上调通了LED和按键现在换到NY8B062F做带ADC的量产板移植步骤是新建工程先选新芯片型号然后确认外设差异——NY8B062F有ADC把ADC例程的文件加进工程再改ny8_config.h里的IO映射。移植过程中最烦的是引脚复用问题。不同型号封装不一样同一个IO可能在不同封装上对应不同物理引脚也可能这个IO在A型号上是普通输入在B型号上默认接了模拟功能。遇到这种问题我的排查顺序是先看数据手册的Pin Function表格确认功能复用再检查Option里的配置有没有把模拟外设意外使能最后看代码寄存器操作是否影响到了复用的功能位。5. 常见问题与排查技巧实录5.1 编译报错与资源溢出最常报的错是ROM/RAM空间不足。ROM溢出时编译器会提示程序空间不够这时候先检查是不是优化等级太低或者某个例程模块被整个文件加进来但实际上只用到其中几个函数。PDS编译器的优化等级可以调试着开高一级体积往往能减少10%到20%。RAM溢出则要检查局部数组是不是太大、有没有在中断里定义了大型临时变量。另一个容易卡住的编译问题是“未定义符号”多半是头文件路径没配好或者某个汇编函数没有在C里正确声明。检查一下工程设置里的include路径以及混编代码的extern声明是否和汇编入口名字完全一致。5.2 烧录失败与芯片锁死烧录失败除了接触不良还有一个常见原因是芯片已经有程序、且代码里把编程引脚配置成了普通IO。这时候烧录器无法进入编程模式需要先擦除芯片。OTP芯片理论上是一次性编程但部分型号支持多次编程直到空间写满我记得有些型号可以擦除后重新烧录具体看官方型号说明。如果烧录器一直报错别硬试同一块芯片先换一片新的验证工具和连接线是否正常。5.3 代码跑飞与复位程序运行一段时间后莫名其妙复位排查思路按概率排序一是看门狗没喂二是中断里清标志位顺序不对三是堆栈溢出。堆栈溢出在C代码里特别难查因为编译器不会直接警告表现就是程序“随机”跑飞。建议把工程里的大数组、递归调用都查一遍NY8系列资源有限根本不适合写递归。某个中断服务函数里如果调用了耗时很长的子函数也会显著增加栈使用和中断嵌套风险。中断里还有一个经典坑进入中断后没有及时清中断标志导致中断反复触发主循环永远抢不到CPU看起来就像程序卡死。写例程时我给每个中断源都加了“先清标志、再处理业务”的注释这条原则请务必遵守。5.4 混编和优化相关的坑开启C编译器优化后如果你在代码里写了空循环延时编译器可能直接把循环优化掉导致延时时间完全不对。解决办法有两种把延时函数单独放到一个C文件里并关掉该文件优化等级或者用内联汇编写延时。我在例程里提供的delay_loops函数就做了这种处理注释里明确写了“这个文件请关闭优化否则延时失效”。汇编和C混编时另一个要命的问题是bank切换。NY8的数据存储器分bankC编译器会自动处理但你自己写的汇编函数访问RAM时编译器不知道你用了哪个bank一旦bank没切对读到的是错误地址的数据而且这种bug极其隐蔽。解决思路是汇编函数尽量只操作当前bank的寄存器如果必须跨bank要按数据手册要求手动切换并恢复现场。这套例程整理出来后我自己又用它做了一款三键触摸台灯和一个电池电量监测模块整体开发效率比以前从零开始写快了非常多。如果你也是刚接触九齐建议别急着写业务代码先把模板工程跑起来然后拿汇编版点灯程序对着数据手册逐行读一遍。读完你会对编译器和寄存器的工作方式有很深的体感后面再踩坑就基本集中在业务逻辑而不是芯片本身了。素材可以在九齐官网和一些电子论坛里找到配合这份例程合集一起用上手速度会快很多。本文还有配套的精品资源点击获取