04/12~04/19周报

本文深入探讨JavaScript中的变量类型,包括基本类型和引用类型的区别,动态属性的使用,以及变量复制和传递的机制。同时,文章详细解析执行环境的概念,包括局部和全局作用域,作用域链的查询过程,以及JavaScript的垃圾收集机制。

【本周任务】
JavaScript(第四章~第五章)
第四章
变量
1.两种类型:基本类型和引用类型(可以为其添加属性和方法,也可以改变删除其属性和方法,动态地添加属性)
2.动态的属性:引用类型的值,我们可以为其添加属性和方法,也可以改变和删除其属性和方法,不能给基本类型的值添加属性
3.复制变量:复制基本类型的值,复制后互不影响,复制引用类型的值时,改变一个变量,另一个就会受到影响
4.传递函数:ECMAScript 中所有函数的参数都是按值传递的。
5.检测类型(instanceof 操作符):alert(person instanceof Object); // 变量 person 是 Object 吗?
6.执行环境及作用域
在局部作用域中定义的变量可以在局部环境中与全局变量互换使用,每个环境都 可以向上搜索作用域链,以查询变量和函数名;但任何环境都不能通过向下搜索作用域链而进入另一个 执行环境。
7.延长作用域链
try-catch 语句的 catch 块;
with 语句。
8.JavaScript 没有块级作用域,使用 var 声明的变量会自动被添加到最接近的环境中。在函数内部,最接近的环境就是函数的局部环境;在 with 语句中,最接近的环境是函数环境。如果初始化变量时没有使用 var 声明,该变量会自动被添加到全局环境。在初始化变量之前,一定要先声明。
9.查询标识符
搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。如果在局部环境中找到
了该标识符,搜索过程停止,变量就绪。如果在局部环境中没有找到该变量名,则继续沿作用域链向上搜索。搜索过程将一直追溯到全局环境的变量对象。
10.JavaScript 具有自动垃圾收集机制
垃圾收集:标记清除和引用计数(循环引用会出现问题)
11.管理内存:一旦数据不再有用,最好通过将其值设置为 null 来释放其引用,这个做法叫做解除引用,解除一个值的引用并不意味着自动回收该值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器下次运行时将其回收。
12.执行环境有全局执行环境和函数执行环境之分
13.基本类型值在内存中占据固定大小的空间,因此被保存在栈内存中,引用类型的值是对象,保存在堆内存中。
第五章

#include <reg52.h> #include <intrins.h> #include <stdio.h> // ---------------------- 新引脚定义(按要求修改) ---------------------- #define DATAPORT P0 // 数码管数据口(P0) sbit DQ = P2^7; // DS18B20引脚(P2.7) sbit Buzzer = P2^0; // 蜂鸣器(P2.0) sbit LED = P2^6; // 模式切换指示灯(P2.6) // 步进电机引脚(P3.0-P3.3) sbit MOTOR_A = P3^0; sbit MOTOR_B = P3^1; sbit MOTOR_C = P3^2; sbit MOTOR_D = P3^3; // 74HC595引脚(P2.1-P2.3) sbit SHCP = P2^3; // 移位时钟 sbit STCP = P2^2; // 存储时钟 sbit DS = P2^1; // 数据 sbit LATCH1 = P2^4; // 数码管位选锁存 // DS1302引脚(P3.4-P3.6) sbit DS1302_CLK = P3^4; sbit DS1302_IO = P3^5; sbit DS1302_CE = P3^6; // 修复语法错误 // 4x4矩阵按键(P1口:行P1.0-P1.3,列P1.4-P1.7) #define KEY_ROW P1 // 行端口 #define KEY_COL P1 // 列端口 // ---------------------- 全局变量 ---------------------- // 步进电机8拍步序(正转,对应MOTOR_A-D) unsigned char code motor_step[] = {0x01,0x03,0x02,0x06,0x04,0x0C,0x08,0x09}; unsigned char motor_current = 0; // 当前步序索引 bit motor_run = 0; // 电机运行标志 bit motor_dir = 0; // 0-正转,1-反转 // 环境参数 unsigned char temp_int = 0; // 温度整数部分(0-100℃) unsigned char temp_dec = 0; // 温度小数部分(0或5,0.5℃精度) unsigned char lux_val = 0; // 光照度(0-255) unsigned char temp_alarm = 30; // 温度报警上限 unsigned char lux_alarm = 180; // 光照报警上限 // 系统状态 unsigned char set_mode = 0; // 0-正常,1-温报警,2-光报警,3-时间调节 unsigned char time_buf[7] = {0,0,12,2,12,20,25}; // 秒分时分日月年(BCD) unsigned char key_flag = 0; // 时间调节字段索引(0-6) unsigned int beep_freq = 0; // 蜂鸣器频率控制 unsigned char key_val = 0; // 矩阵按键值(0-15,无按键为0xFF) unsigned char disp_buf[32]; // 显示缓存 // 数码管段码表(共阴极,0-9、A-F、.、空格、L、M) unsigned char code seg_table[] = { 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8, // 共阳极0-7 0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E, // 共阳极8-F 0x40,0xFF,0xC7,0x84 // 共阳极.、空格、L、M }; // 数码管位选(8位数码管,从左到右1-8位) unsigned char code bit_table[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; // ---------------------- 函数原型声明(新增:解决缺少原型报错) ---------------------- void seg_show_bit(unsigned char bit_num, unsigned char seg_idx); void seg_clear(void); void delay_us(unsigned int us); void delay_ms(unsigned int ms); void hc595_write_byte(unsigned char dat); void seg_scan_display(void); void seg_update_normal(void); void seg_show_time(void); void seg_show_set(void); bit ds18b20_init(void); void ds18b20_write_byte(unsigned char dat); unsigned char ds18b20_read_byte(void); void ds18b20_read_temp(void); unsigned char lux_detect_rc(void); void ds1302_write_byte(unsigned char addr, unsigned char dat); unsigned char ds1302_read_byte(unsigned char addr); void ds1302_init(void); void ds1302_read_time(void); unsigned char key_scan(void); void key_process(void); void motor_control(void); void timer1_init(void); void beep_control(void); // ---------------------- 基础延时函数 ---------------------- void delay_us(unsigned int us) { while(us--); } void delay_ms(unsigned int ms) { unsigned int i,j; for(i=ms;i>0;i--) for(j=110;j>0;j--); } // ---------------------- 74HC595驱动模块(数码管) ---------------------- // 写入1字节数据到74HC595 void hc595_write_byte(unsigned char dat) { unsigned char i; for(i = 0; i < 8; i++) { SHCP = 0; // 先拉低时钟 DS = (dat & 0x80) ? 1 : 0; // 发送最高位 dat <<= 1; SHCP = 1; // 上升沿移位 delay_us(1); } } // 恢复缺失的 seg_show_bit 函数(原逻辑不变) void seg_show_bit(unsigned char bit_num, unsigned char seg_idx) { LATCH1 = 0; hc595_write_byte(seg_table[seg_idx]); // 段码 hc595_write_byte(bit_table[bit_num]); // 位选 STCP = 1; delay_us(1); STCP = 0; delay_ms(1); // 消影 } // 恢复缺失的 seg_clear 函数(原逻辑不变) void seg_clear() { unsigned char i; for(i=0;i<8;i++) { seg_show_bit(i, 17); // 显示空格 } } // 全局变量添加 unsigned char display_digit = 0; // 当前扫描的数码管位 unsigned char display_buffer[8] = {17,17,17,17,17,17,17,17}; // 显示缓冲区,初始为空 // 统一的动态扫描函数 void seg_scan_display(void) { // 先关闭所有数码管避免重影 LATCH1 = 0; hc595_write_byte(0x00); // 位选全关 hc595_write_byte(seg_table[display_buffer[display_digit]]); // 发送当前位段码 hc595_write_byte(bit_table[display_digit]); // 开启当前位数码管 LATCH1 = 1; display_digit = (display_digit + 1) % 8; // 移动到下一位 } void seg_update_normal(void) { // 温度显示:XX.X (第0-3位) display_buffer[0] = temp_int / 10; display_buffer[1] = temp_int % 10; display_buffer[2] = 16; // 小数点 display_buffer[3] = temp_dec; // 光照显示:XXX (第4-6位) display_buffer[4] = lux_val / 100; display_buffer[5] = (lux_val % 100) / 10; display_buffer[6] = lux_val % 10; // 报警指示 (第7位) if((temp_int > temp_alarm) || (lux_val > lux_alarm)) { display_buffer[7] = 10; // 显示'A'表示报警 } else { display_buffer[7] = 17; // 空格 } } // 时间显示模式:显示日期时间(20YY-MM-DD HH:MM) void seg_show_time() { // 第1-2位:年(YY) seg_show_bit(0, (time_buf[6]>>4)&0x0F); seg_show_bit(1, time_buf[6]&0x0F); // 第3位:分隔符(-) seg_show_bit(2, 17); // 用空格代替 // 第4-5位:月(MM) seg_show_bit(3, (time_buf[4]>>4)&0x0F); seg_show_bit(4, time_buf[4]&0x0F); // 第6-7位:日(DD) seg_show_bit(5, (time_buf[3]>>4)&0x0F); seg_show_bit(6, time_buf[3]&0x0F); // 延时切换显示时分 delay_ms(500); seg_clear(); // 第1-2位:时(HH) seg_show_bit(0, (time_buf[2]>>4)&0x0F); seg_show_bit(1, time_buf[2]&0x0F); // 第3位:分隔符(:) seg_show_bit(2, 17); // 第4-5位:分(MM) seg_show_bit(3, (time_buf[1]>>4)&0x0F); seg_show_bit(4, time_buf[1]&0x0F); // 第6-7位:秒(SS) seg_show_bit(5, (time_buf[0]>>4)&0x0F); seg_show_bit(6, time_buf[0]&0x0F); delay_ms(500); } // 设定模式显示:温度/光照报警值、时间调节 void seg_show_set() { // 修复:将case内的数组移到函数开头定义(C51不支持case内定义变量) unsigned char flash_bit[] = {6,4,1,5,3,0,0}; // 字段对应数码管位(0-秒,1-分,2-时,3-日,4-月,6-年) switch(set_mode) { case 1: // 温度报警设定 seg_show_bit(0, 19); // M(Mode) seg_show_bit(1, 18); // L(Temp) seg_show_bit(2, 17); seg_show_bit(3, temp_alarm/10); seg_show_bit(4, temp_alarm%10); break; case 2: // 光照报警设定 seg_show_bit(0, 19); // M seg_show_bit(1, 18); // L(Lux) seg_show_bit(2, 17); seg_show_bit(3, lux_alarm/100); seg_show_bit(4, (lux_alarm%100)/10); seg_show_bit(5, lux_alarm%10); break; case 3: // 时间调节(闪烁当前字段) seg_show_time(); // 闪烁对应字段 seg_show_bit(flash_bit[key_flag], 17); // 清空字段 delay_ms(300); break; } } // ---------------------- DS18B20温度模块(新引脚DQ=P2.7) ---------------------- bit ds18b20_init() { bit ack; DQ = 0; delay_us(750); // 拉低480-960us DQ = 1; delay_us(15); // 等待应答 ack = DQ; delay_us(200); // 等待剩余时间 return !ack; // 应答成功返回1 } void ds18b20_write_byte(unsigned char dat) { unsigned char i; for(i=0;i<8;i++) { DQ = 0; delay_us(2); DQ = dat&0x01; delay_us(60); DQ = 1; dat >>= 1; } } unsigned char ds18b20_read_byte() { unsigned char i, dat=0; for(i=0;i<8;i++) { DQ = 0; delay_us(2); DQ = 1; delay_us(10); dat >>= 1; if(DQ) dat |= 0x80; delay_us(50); } return dat; } void ds18b20_read_temp() { unsigned int temp; if(ds18b20_init()) { ds18b20_write_byte(0xCC); // 跳过ROM ds18b20_write_byte(0x44); // 启动转换 delay_ms(100); ds18b20_init(); ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // 读取数据 temp = ds18b20_read_byte(); temp |= (unsigned int)ds18b20_read_byte() << 8; temp_int = temp >> 1; // 整数部分 temp_dec = (temp & 0x01) ? 5 : 0; // 小数部分(0.5℃) } } // ---------------------- RC充放电光照模块(复用P3.7,无ADC) ---------------------- sbit LUX_IO = P3^7; // 光照检测IO口(P3.7,未被占用) unsigned char lux_detect_rc() { unsigned int count = 0; // 充电 LUX_IO = 1; delay_us(100); // 放电计时 LUX_IO = 1; // 输入模式 while(LUX_IO == 1 && count < 255) { count++; delay_us(10); } return 255 - count; // 光照越强,数值越大 } // ---------------------- DS1302时钟模块(新引脚P3.4-P3.6) ---------------------- void ds1302_write_byte(unsigned char addr, unsigned char dat) { unsigned char i; DS1302_CE = 0; DS1302_CLK = 0; DS1302_CE = 1; // 写地址 for(i=0;i<8;i++) { DS1302_IO = addr&0x01; DS1302_CLK = 1; DS1302_CLK = 0; addr >>= 1; } // 写数据 for(i=0;i<8;i++) { DS1302_IO = dat&0x01; DS1302_CLK = 1; DS1302_CLK = 0; dat >>= 1; } DS1302_CE = 0; } unsigned char ds1302_read_byte(unsigned char addr) { unsigned char i, dat=0; DS1302_CE = 0; DS1302_CLK = 0; DS1302_CE = 1; // 写地址 for(i=0;i<8;i++) { DS1302_IO = addr&0x01; DS1302_CLK = 1; DS1302_CLK = 0; addr >>= 1; } // 读数据 for(i=0;i<8;i++) { dat >>= 1; if(DS1302_IO) dat |= 0x80; DS1302_CLK = 1; DS1302_CLK = 0; } DS1302_CE = 0; return dat; } void ds1302_init() { ds1302_write_byte(0x8E, 0x00); // 关闭写保护 // 初始化时间:2025-12-02 12:00:00 ds1302_write_byte(0x80, 0x00); // 秒 ds1302_write_byte(0x82, 0x00); // 分 ds1302_write_byte(0x84, 0x12); // 时 ds1302_write_byte(0x86, 0x02); // 日 ds1302_write_byte(0x88, 0x12); // 月 ds1302_write_byte(0x8A, 0x02); // 周 ds1302_write_byte(0x8C, 0x25); // 年 ds1302_write_byte(0x8E, 0x80); // 开启写保护 } void ds1302_read_time() { time_buf[0] = ds1302_read_byte(0x81) & 0x7F; // 秒 time_buf[1] = ds1302_read_byte(0x83); // 分 time_buf[2] = ds1302_read_byte(0x85) & 0x3F; // 时 time_buf[3] = ds1302_read_byte(0x87); // 日 time_buf[4] = ds1302_read_byte(0x89) & 0x1F; // 月 time_buf[5] = ds1302_read_byte(0x8B); // 周 time_buf[6] = ds1302_read_byte(0x8D); // 年 } // ---------------------- 4x4矩阵按键模块(P1口) ---------------------- // 按键扫描:返回按键值(0-15,无按键返回0xFF) unsigned char key_scan() { unsigned char row, col; unsigned char temp; KEY_ROW = 0x0F; // 行拉低,列高电平 delay_ms(10); // 消抖 temp = KEY_ROW & 0x0F; if(temp == 0x0F) return 0xFF; // 无按键 // 检测行 for(row=0;row<4;row++) { KEY_ROW = 0xFF; KEY_ROW &= ~(1<<row); delay_us(20); temp = KEY_ROW & 0x0F; if(temp != 0x0F) break; } // 检测列 for(col=0;col<4;col++) { if(!(temp & (1<<col))) break; } // 等待按键释放 while((KEY_ROW & 0x0F) != 0x0F); return row*4 + col; // 按键值:0-15 } // 按键功能映射 void key_process() { unsigned char i; // 修复:提前声明循环变量(C51不支持for内定义) key_val = key_scan(); if(key_val == 0xFF) return; // 无按键 LED = 1; // 按键触发时LED亮 switch(key_val) { case 0: // 按键0:SET(模式切换) set_mode++; if(set_mode > 3) set_mode = 0; // 时间调节模式切换写保护 if(set_mode == 3) ds1302_write_byte(0x8E, 0x00); else if(set_mode == 0) ds1302_write_byte(0x8E, 0x80); // LED闪烁提示模式切换(修复:用提前声明的i) for(i=0;i<3;i++) { LED = ~LED; delay_ms(100); } LED = 0; break; case 1: // 按键1:ADD(加) switch(set_mode) { case 1: // 温度报警+ temp_alarm++; if(temp_alarm > 100) temp_alarm = 0; break; case 2: // 光照报警+ lux_alarm++; if(lux_alarm > 255) lux_alarm = 0; break; case 3: // 时间调节+ time_buf[key_flag]++; // 边界处理 if(key_flag==0 && time_buf[0]>=0x60) time_buf[0] = 0; if(key_flag==1 && time_buf[1]>=0x60) time_buf[1] = 0; if(key_flag==2 && time_buf[2]>=0x24) time_buf[2] = 0; if(key_flag==3 && time_buf[3]>=0x32) time_buf[3] = 0x01; if(key_flag==4 && time_buf[4]>=0x13) time_buf[4] = 0x01; if(key_flag==6 && time_buf[6]>=0x99) time_buf[6] = 0x00; ds1302_write_byte(0x80 + key_flag*2, time_buf[key_flag]); break; } break; case 2: // 按键2:SUB(减) switch(set_mode) { case 1: // 温度报警- temp_alarm--; if(temp_alarm < 0) temp_alarm = 100; break; case 2: // 光照报警- lux_alarm--; if(lux_alarm < 0) lux_alarm = 255; break; case 3: // 时间调节- time_buf[key_flag]--; if(key_flag==0 && time_buf[0] < 0) time_buf[0] = 0x59; if(key_flag==1 && time_buf[1] < 0) time_buf[1] = 0x59; if(key_flag==2 && time_buf[2] < 0) time_buf[2] = 0x23; if(key_flag==3 && time_buf[3] < 0x01) time_buf[3] = 0x31; if(key_flag==4 && time_buf[4] < 0x01) time_buf[4] = 0x12; if(key_flag==6 && time_buf[6] < 0) time_buf[6] = 0x99; ds1302_write_byte(0x80 + key_flag*2, time_buf[key_flag]); break; } break; case 3: // 按键3:字段切换(时间调节模式) if(set_mode == 3) { key_flag++; if(key_flag > 6) key_flag = 0; } break; case 4: // 按键4:车窗正转(FWD) motor_run = 1; motor_dir = 0; break; case 5: // 按键5:车窗反转(REV) motor_run = 1; motor_dir = 1; break; case 6: // 按键6:车窗停止(STOP) motor_run = 0; break; } LED = 0; // 按键处理完成LED灭 } // ---------------------- 步进电机控制模块(新引脚P3.0-P3.3) ---------------------- void motor_control() { unsigned char step_val; // 修复:用中间变量过渡,避免sbit赋值解析异常 if(motor_run) { step_val = motor_step[motor_current]; // 读取当前步序值 // 按步序设置电机引脚(修复sbit赋值语法) MOTOR_A = (step_val & 0x01) ? 1 : 0; MOTOR_B = (step_val & 0x02) ? 1 : 0; MOTOR_C = (step_val & 0x04) ? 1 : 0; MOTOR_D = (step_val & 0x08) ? 1 : 0; // 步序索引更新 if(motor_dir == 0) { // 正转 motor_current++; if(motor_current >= 8) motor_current = 0; } else { // 反转 motor_current--; if(motor_current >= 8) motor_current = 7; } delay_ms(5); // 调节转速,无抖动 } else { // 停止电机(所有引脚置低) MOTOR_A = 0; MOTOR_B = 0; MOTOR_C = 0; MOTOR_D = 0; } } // ---------------------- 蜂鸣器控制模块(P2.0) ---------------------- void timer1_init() { TMOD |= 0x10; // 定时器1模式1(16位) ET1 = 1; // 使能中断 EA = 1; // 开总中断 } void timer1_isr() interrupt 3 { TH1 = (65536 - beep_freq) / 256; TL1 = (65536 - beep_freq) % 256; Buzzer = ~Buzzer; // 电平翻转产生方波 } void beep_control() { int temp_diff = temp_int - temp_alarm; int lux_diff = lux_val - lux_alarm; int max_diff = (temp_diff > lux_diff) ? temp_diff : lux_diff; if(max_diff > 0) { // 超限值越大,蜂鸣越急促(频率越高) if(max_diff <= 5) beep_freq = 4000; else if(max_diff <= 10) beep_freq = 2000; else beep_freq = 1000; TR1 = 1; LED = 1; // 报警时LED同步亮 } else { TR1 = 0; Buzzer = 1; LED = 0; } } // ---------------------- 主函数 ---------------------- void main() { // 初始化部分保持不变 ds1302_init(); timer1_init(); seg_clear(); delay_ms(100); LED = 0; while(1) { // 数据采集(每100ms一次) static unsigned int collect_count = 0; if(++collect_count >= 100) { collect_count = 0; ds18b20_read_temp(); lux_val = lux_detect_rc(); ds1302_read_time(); } // 按键处理 key_process(); // 报警控制 beep_control(); // 电机控制 motor_control(); // 显示处理(主函数中) switch(set_mode) { case 0: // 正常模式 seg_update_normal(); break; case 1: // 温度报警设置 seg_show_set(); // 新增:调用设置模式显示函数 break; case 2: // 光照报警设置 seg_show_set(); // 新增:调用设置模式显示函数 break; case 3: // 时间设置 seg_show_set(); // 新增:调用设置模式显示函数 break; } // 执行动态扫描(每次循环都执行) seg_scan_display(); delay_ms(2); // 控制整体刷新率 } }要求运行上述代码实现检测车内温度、光照度并根据设定的温度或者光照度值自动打开车窗,当温度或光照度超过设定的报警值时发出蜂鸣报警,值越高,蜂鸣报警声音越急促。 2、将报警信息和测量参数显示在仪表盘上; 3、车内环境温度测量精度0.5度,范围0-100度; 4、车窗玻璃位置可任意调节(调节步进电机转动的位置); 5、日历、时间显示; 等功能,但目前单片机上数码管不亮,该如何解决
12-03
### 一、基础模块(同步/边沿检测/分频) #### 1. SyncTwoStage.v(异步信号同步,消除亚稳态) ```verilog module SyncTwoStage( input wire clk, // 目标时钟域(SYS_CLK) input wire rst_n, // 低电平复位(0=复位) input wire din, // 异步输入(外部传感器SIGNAL) output reg dout // 同步后输出(无亚稳态) ); reg din_sync1; // 第一级同步寄存器 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin din_sync1 <= 1'b0; dout <= 1'b0; end else begin din_sync1 <= din; // 第一级采样 dout <= din_sync1; // 第二级同步 end end endmodule ``` #### 2. EdgeDetector.v(边沿检测,生成1周期脉冲) ```verilog module EdgeDetector( input wire SYS_CLK, // 系统时钟 input wire RST_N, // 低电平复位 input wire sig_in, // 同步输入信号 output reg rise, // 上升沿脉冲(1周期) output reg fall // 下降沿脉冲(1周期) ); reg sig_prev; // 前态寄存器 always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin sig_prev <= 1'b0; rise <= 1'b0; fall <= 1'b0; end else begin sig_prev <= sig_in; rise <= sig_in & ~sig_prev; // 上升沿:当前1,前态0 fall <= ~sig_in & sig_prev; // 下降沿:当前0,前态1 end end endmodule ``` #### 3. Div2Gen.v(2分频生成,50%占空比) ```verilog module Div2Gen( input wire SYS_CLK, // 系统时钟 input wire RST_N, // 低电平复位 input wire sync_signal, // 同步输入信号(来自SyncTwoStage) output reg div2 // 2分频输出 ); reg signal_prev; // 前态寄存器(检测上升沿) always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin signal_prev <= 1'b0; div2 <= 1'b0; end else begin signal_prev <= sync_signal; if (sync_signal & ~signal_prev) begin // 检测上升沿 div2 <= ~div2; // 翻转输出,实现50%占空比 end end end endmodule ``` #### 4. DivNGen.v(N分频生成,支持8/16/24/32/40分频) ```verilog module DivNGen( input wire SYS_CLK, // 系统时钟 input wire RST_N, // 低电平复位 input wire [2:0] WHEEL, // 分频配置:001=8,010=16,011=24,100=32,101=40 input wire sync_signal, // 同步输入信号 output reg div_N, // N分频输出(50%占空比) output reg wheel_valid // 配置有效标志(1=有效) ); reg [5:0] div_cnt; // 计数器(最大支持40分频) reg [5:0] max_cnt; // 计数阈值(N/2 - 1) reg signal_prev; // 前态寄存器 reg first_edge; // 首个上升沿标记(同步启动) // 分频系数配置(组合逻辑) always @(*) begin case(WHEEL) 3'b001: begin max_cnt = 6'd3; wheel_valid = 1'b1; end // 8分频:(8/2)-1=3 3'b010: begin max_cnt = 6'd7; wheel_valid = 1'b1; end // 16分频:(16/2)-1=7 3'b011: begin max_cnt = 6'd11; wheel_valid = 1'b1; end // 24分频:(24/2)-1=11 3'b100: begin max_cnt = 6'd15; wheel_valid = 1'b1; end // 32分频:(32/2)-1=15 3'b101: begin max_cnt = 6'd19; wheel_valid = 1'b1; end // 40分频:(40/2)-1=19 default: begin max_cnt = 6'd3; wheel_valid = 1'b0; end // 无效配置 endcase end // 首个上升沿检测 always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin signal_prev <= 1'b0; first_edge <= 1'b1; end else begin signal_prev <= sync_signal; if (first_edge && (sync_signal & ~signal_prev)) begin first_edge <= 1'b0; end end end // N分频逻辑 always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin div_cnt <= 6'd0; div_N <= 1'b0; end else if (first_edge && (sync_signal & ~signal_prev)) begin div_N <= ~div_N; // 首个上升沿直接翻转 end else if (!first_edge && wheel_valid && (sync_signal & ~signal_prev)) begin if (div_cnt == max_cnt) begin div_N <= ~div_N; // 计数到阈值翻转 div_cnt <= 6'd0; end else begin div_cnt <= div_cnt + 1'b1; end end end endmodule ``` ### 二、核心模块(计数锁存/FIFO/命令缓存) #### 5. CntLatch1.v(2分频计数锁存,双缓冲+精准清零) ```verilog module CntLatch1( input wire SYS_CLK, // 系统时钟 input wire RST_N, // 低电平复位 input wire STM32_RD_DONE, // 读取完成(全部数据已读) input wire div2_rise, // 2分频上升沿(计数启动) input wire div2_fall, // 2分频下降沿(计数停止) output reg [23:0] latch1_data, // 锁存数据(供FIFO) output reg latch1_valid, // 数据有效标志 output reg latch1_overflow, // 溢出标志(1=计数超24位) input wire fifo_wr_ack // FIFO写确认(数据已入FIFO) ); reg [23:0] cnt1; // 24位计数器(最大16777215) reg en_cnt1; // 计数使能 reg overflow_flag; // 溢出临时标志 reg [23:0] latch_buf; // 双缓冲(FIFO满时暂存,防覆盖) reg buf_valid; // 缓冲有效标志 // 计数控制逻辑 always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin cnt1 <= 24'd0; en_cnt1 <= 1'b0; overflow_flag <= 1'b0; end else if (STM32_RD_DONE) begin cnt1 <= 24'd0; // 读取完成,计数器清零 en_cnt1 <= 1'b0; overflow_flag <= 1'b0; end else if (div2_rise) begin en_cnt1 <= 1'b1; // 上升沿启动计数 overflow_flag <= 1'b0; end else if (div2_fall) begin en_cnt1 <= 1'b0; // 下降沿停止计数 latch_buf <= cnt1; // 锁存数据到双缓冲 buf_valid <= 1'b1; latch1_overflow <= overflow_flag; end else if (en_cnt1) begin if (cnt1 == 24'hFFFFFF) begin overflow_flag <= 1'b1; // 检测溢出 cnt1 <= 24'hFFFFFF; // 保持最大值,避免翻转 end else begin cnt1 <= cnt1 + 1'b1; // 正常计数 end end end // 双缓冲→FIFO输出逻辑(FIFO空闲时自动写入) always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin latch1_data <= 24'd0; latch1_valid <= 1'b0; end else if (fifo_wr_ack) begin latch1_valid <= 1'b0; // FIFO写入成功,清除有效标志 buf_valid <= 1'b0; // 清空缓冲 end else if (buf_valid && !latch1_valid) begin latch1_data <= latch_buf; // 缓冲有数据且FIFO空闲,输出到FIFO latch1_valid <= 1'b1; end end // 读取完成强制清缓冲(确保锁存器完全复位) always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin buf_valid <= 1'b0; end else if (STM32_RD_DONE) begin buf_valid <= 1'b0; latch1_valid <= 1'b0; end end endmodule ``` #### 6. CntLatch2.v(N分频计数锁存,双缓冲+独立异常编码) ```verilog module CntLatch2( input wire SYS_CLK, // 系统时钟 input wire RST_N, // 低电平复位 input wire STM32_RD_DONE, // 读取完成(全部数据已读) input wire div_N_rise, // N分频上升沿(计数启动) input wire div_N_fall, // N分频下降沿(计数停止) input wire wheel_valid, // 分频配置有效标志 output reg [23:0] latch2_data, // 锁存数据(供FIFO) output reg latch2_valid, // 数据有效标志 output reg latch2_overflow, // 溢出标志(1=计数超24位) output reg latch2_invalid_cfg, // 配置无效标志(1=无效) input wire fifo_wr_ack // FIFO写确认(数据已入FIFO) ); reg [23:0] cnt2; // 24位计数器 reg en_cnt2; // 计数使能 reg overflow_flag; // 溢出临时标志 reg [23:0] latch_buf; // 双缓冲(防覆盖) reg buf_valid; // 缓冲有效标志 reg invalid_cfg_reg; // 配置无效临时标志 // 计数控制逻辑 always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin cnt2 <= 24'd0; en_cnt2 <= 1'b0; overflow_flag <= 1'b0; invalid_cfg_reg <= 1'b0; end else if (STM32_RD_DONE) begin cnt2 <= 24'd0; en_cnt2 <= 1'b0; overflow_flag <= 1'b0; invalid_cfg_reg <= 1'b0; end else if (div_N_rise) begin en_cnt2 <= 1'b1; overflow_flag <= 1'b0; invalid_cfg_reg <= ~wheel_valid; // 记录配置有效性 end else if (div_N_fall) begin en_cnt2 <= 1'b0; latch_buf <= cnt2; buf_valid <= 1'b1; latch2_overflow <= overflow_flag; latch2_invalid_cfg <= invalid_cfg_reg; end else if (en_cnt2 && wheel_valid) begin if (cnt2 == 24'hFFFFFF) begin overflow_flag <= 1'b1; cnt2 <= 24'hFFFFFF; end else begin cnt2 <= cnt2 + 1'b1; end end end // 双缓冲→FIFO输出逻辑 always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin latch2_data <= 24'd0; latch2_valid <= 1'b0; end else if (fifo_wr_ack) begin latch2_valid <= 1'b0; buf_valid <= 1'b0; end else if (buf_valid && !latch2_valid) begin latch2_data <= latch_buf; latch2_valid <= 1'b1; end end // 读取完成强制清缓冲 always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin buf_valid <= 1'b0; end else if (STM32_RD_DONE) begin buf_valid <= 1'b0; latch2_valid <= 1'b0; end end endmodule ``` #### 7. SyncFIFO.v(数据FIFO,防溢出/下溢+写确认) ```verilog module SyncFIFO #( parameter DATA_WIDTH = 24, // 数据宽度(匹配锁存器) parameter DEPTH = 16, // FIFO深度(2的幂,支持16个数据) parameter HALF_DEPTH = 8 // 半满阈值 )( input wire clk, // 系统时钟 input wire rst_n, // 低电平复位 input wire wr_en, // 写使能(1=允许写入,需!full) input wire [DATA_WIDTH-1:0] wr_data, // 写入数据 input wire rd_en, // 读使能(1=允许读取,需!empty) output reg [DATA_WIDTH-1:0] rd_data, // 读出数据 output reg empty, // 空标志(1=无数据) output reg full, // 满标志(1=已满) output reg half_full, // 半满标志(1=数据≥HALF_DEPTH) output reg wr_ack // 写确认(1=数据已写入) ); reg [DATA_WIDTH-1:0] fifo_mem[DEPTH-1:0]; // FIFO存储数组 localparam PTR_WIDTH = $clog2(DEPTH); // 指针位宽(自动计算) reg [PTR_WIDTH-1:0] wr_ptr; // 写指针(指向下次写入地址) reg [PTR_WIDTH-1:0] rd_ptr; // 读指针(指向下次读取地址) reg [PTR_WIDTH-1:0] data_cnt; // 当前数据量(0~DEPTH) // 空/满/半满标志+数据计数(修复溢出/下溢) always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_cnt <= {PTR_WIDTH{1'b0}}; empty <= 1'b1; full <= 1'b0; half_full <= 1'b0; wr_ack <= 1'b0; end else begin wr_ack <= 1'b0; case ({wr_en, rd_en}) 2'b00: data_cnt <= data_cnt; // 无读写,计数不变 2'b01: data_cnt <= (data_cnt > 0) ? data_cnt - 1 : 0; // 只读,防下溢 2'b10: begin // 只写,防上溢 if (data_cnt < DEPTH) begin data_cnt <= data_cnt + 1; wr_ack <= 1'b1; // 写成功,输出确认 end end 2'b11: data_cnt <= data_cnt; // 同时读写,计数不变 endcase empty <= (data_cnt == 0); full <= (data_cnt == DEPTH); half_full <= (data_cnt >= HALF_DEPTH); end end // 写数据逻辑 always @(posedge clk or negedge rst_n) begin integer i; if (!rst_n) begin wr_ptr <= {PTR_WIDTH{1'b0}}; for (i = 0; i < DEPTH; i = i + 1) begin fifo_mem[i] <= {DATA_WIDTH{1'b0}}; // 复位时FIFO清零 end end else if (wr_en && !full) begin fifo_mem[wr_ptr] <= wr_data; // 写入数据到当前地址 wr_ptr <= (wr_ptr == DEPTH - 1) ? {PTR_WIDTH{1'b0}} : wr_ptr + 1; // 指针循环 end end // 读数据逻辑 always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rd_ptr <= {PTR_WIDTH{1'b0}}; rd_data <= {DATA_WIDTH{1'b0}}; end else if (rd_en && !empty) begin rd_data <= fifo_mem[rd_ptr]; // 读取当前地址数据 rd_ptr <= (rd_ptr == DEPTH - 1) ? {PTR_WIDTH{1'b0}} : rd_ptr + 1; // 指针循环 end end endmodule ``` #### 8. CmdFIFO.v(命令缓冲区,支持连续命令接收) ```verilog module CmdFIFO #( parameter DATA_WIDTH = 8, // 命令宽度(UART字节) parameter DEPTH = 4 // 缓存深度(支持4个连续命令) )( input wire clk, // 系统时钟 input wire rst_n, // 低电平复位 input wire wr_en, // 写使能(UART接收命令) input wire [DATA_WIDTH-1:0] wr_data, // 写入命令(来自UART_RX) input wire rd_en, // 读使能(处理命令) output reg [DATA_WIDTH-1:0] rd_data, // 读出命令(供处理) output reg empty, // 空标志(1=无命令) output reg full // 满标志(1=命令缓存满) ); reg [DATA_WIDTH-1:0] fifo_mem[DEPTH-1:0]; // 命令存储数组 localparam PTR_WIDTH = $clog2(DEPTH); // 指针位宽 reg [PTR_WIDTH-1:0] wr_ptr; // 写指针 reg [PTR_WIDTH-1:0] rd_ptr; // 读指针 reg [PTR_WIDTH-1:0] data_cnt; // 命令计数 // 空/满标志+计数(防溢出) always @(posedge clk or negedge rst_n) begin if (!rst_n) begin data_cnt <= {PTR_WIDTH{1'b0}}; empty <= 1'b1; full <= 1'b0; end else begin case ({wr_en, rd_en}) 2'b00: data_cnt <= data_cnt; 2'b01: data_cnt <= (data_cnt > 0) ? data_cnt - 1 : 0; 2'b10: data_cnt <= (data_cnt < DEPTH) ? data_cnt + 1 : DEPTH; 2'b11: data_cnt <= data_cnt; endcase empty <= (data_cnt == 0); full <= (data_cnt == DEPTH); end end // 写命令逻辑(UART接收命令存入) always @(posedge clk or negedge rst_n) begin integer i; if (!rst_n) begin wr_ptr <= {PTR_WIDTH{1'b0}}; for (i = 0; i < DEPTH; i = i + 1) begin fifo_mem[i] <= {DATA_WIDTH{1'b0}}; end end else if (wr_en && !full) begin fifo_mem[wr_ptr] <= wr_data; wr_ptr <= (wr_ptr == DEPTH - 1) ? {PTR_WIDTH{1'b0}} : wr_ptr + 1; end end // 读命令逻辑(处理模块读取命令) always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rd_ptr <= {PTR_WIDTH{1'b0}}; rd_data <= {DATA_WIDTH{1'b0}}; end else if (rd_en && !empty) begin rd_data <= fifo_mem[rd_ptr]; rd_ptr <= (rd_ptr == DEPTH - 1) ? {PTR_WIDTH{1'b0}} : rd_ptr + 1; end end endmodule ``` ### 三、通信控制模块(UART收发+命令处理+中断) #### 9. UART_BaudGen.v(UART波特率发生器,16倍采样时钟) ```verilog module UART_BaudGen #( parameter SYS_CLK_FREQ = 50_000_000, // 系统时钟频率(50MHz) parameter BAUD_RATE = 115200 // 目标波特率(115200) )( input wire clk, // 系统时钟 input wire rst_n, // 低电平复位 output reg baud_clk_16x // 16倍波特率采样时钟(高脉冲有效) ); localparam DIV_CNT = SYS_CLK_FREQ / (BAUD_RATE * 16) - 1; // 分频系数 reg [15:0] cnt; // 计数器(支持最大分频系数65535) always @(posedge clk or negedge rst_n) begin if (!rst_n) begin cnt <= 16'd0; baud_clk_16x <= 1'b0; end else begin if (cnt == DIV_CNT) begin cnt <= 16'd0; baud_clk_16x <= 1'b1; // 生成1周期采样脉冲 end else begin cnt <= cnt + 1'b1; baud_clk_16x <= 1'b0; end end end endmodule ``` #### 10. STM32Comm_UART_FIFO.v(核心通信控制,整合UART+FIFO+命令) ```verilog module STM32Comm_UART_FIFO #( parameter SYS_CLK_FREQ = 50_000_000, // 系统时钟频率 parameter BAUD_RATE = 115200 // UART波特率 )( input wire SYS_CLK, // 系统时钟 input wire RST_N, // 低电平复位 // 锁存器接口 input wire [23:0] latch1_data,// 锁存器1数据 input wire latch1_valid,// 锁存器1有效 input wire latch1_overflow,// 锁存器1溢出 input wire [23:0] latch2_data,// 锁存器2数据 input wire latch2_valid,// 锁存器2有效 input wire latch2_overflow,// 锁存器2溢出 input wire latch2_invalid_cfg,// 锁存器2配置无效 output reg fifo1_wr_ack,// FIFO1写确认(给CntLatch1) output reg fifo2_wr_ack,// FIFO2写确认(给CntLatch2) output reg STM32_RD_DONE,// 读取完成(给锁存器清零) // UART物理接口 input wire UART_RX, // UART接收(来自STM32) output reg UART_TX, // UART发送(给STM32) // 系统状态输出 output reg FPGA_INT, // 1周期中断脉冲(给STM32) output wire FPGA_DATA_RDY, // 数据就绪(任一FIFO非空) output wire FIFO1_FULL, // FIFO1满标志 output wire FIFO2_FULL, // FIFO2满标志 output wire FIFO1_HALF_FULL,// FIFO1半满标志 output wire FIFO2_HALF_FULL,// FIFO2半满标志 output wire LATCH1_OVERFLOW,// 锁存器1溢出报警 output wire LATCH2_OVERFLOW,// 锁存器2溢出报警 output wire LATCH2_INVALID_CFG // 锁存器2配置无效报警 ); // 命令定义(STM32→FPGA) localparam CMD_READ_FIFO1 = 8'h01; // 读取FIFO1(2分频数据) localparam CMD_READ_FIFO2 = 8'h02; // 读取FIFO2(N分频数据) localparam CMD_CLEAR_FIFO1 = 8'h03; // 清除FIFO1 localparam CMD_CLEAR_FIFO2 = 8'h04; // 清除FIFO2 localparam CMD_CLEAR_ALL = 8'h05; // 清除所有FIFO+锁存器 // 状态编码定义(FPGA→STM32) localparam DATA_EMPTY = 24'h000000; // FIFO空(无数据) localparam DATA_OVERFLOW = 24'hFFFFFF; // 计数溢出 localparam DATA_INVALID_CFG = 24'hFF0000; // 配置无效(仅FIFO2) // 内部信号 wire baud_clk_16x; // 16倍波特率采样时钟 wire [7:0] uart_rx_data; // UART接收数据 wire uart_rx_done; // UART接收完成 reg uart_tx_en; // UART发送使能 reg [7:0] uart_tx_data; // UART发送数据 wire uart_tx_busy; // UART发送忙 // 命令缓冲区信号 wire cmd_fifo_wr_en = uart_rx_done; // 接收完成自动写命令 wire [7:0] cmd_fifo_wr_data = uart_rx_data; wire cmd_fifo_rd_en; // 命令读取使能 wire [7:0] cmd_fifo_rd_data; // 读出命令 wire cmd_fifo_empty; // 命令缓冲区空 wire cmd_fifo_full; // 命令缓冲区满 // FIFO1信号(2分频数据缓存) wire fifo1_wr_en = latch1_valid & ~FIFO1_FULL; wire [23:0] fifo1_wr_data = latch1_data; wire fifo1_rd_en; wire [23:0] fifo1_rd_data; wire fifo1_empty; // FIFO2信号(N分频数据缓存) wire fifo2_wr_en = latch2_valid & ~FIFO2_FULL; wire [23:0] fifo2_wr_data = latch2_data; wire fifo2_rd_en; wire [23:0] fifo2_rd_data; wire fifo2_empty; // 发送状态机(24位数据分3字节发送:高→中→低) localparam S_TX_IDLE = 3'd0; // 发送空闲 localparam S_TX_HIGH = 3'd1; // 发送高8位 localparam S_TX_MID = 3'd2; // 发送中8位 localparam S_TX_LOW = 3'd3; // 发送低8位 reg [2:0] tx_state; // 发送状态 reg [23:0] tx_data_buf; // 发送数据缓冲 reg cmd_process_done; // 命令处理完成标志 // 1. 例化波特率发生器 UART_BaudGen #( .SYS_CLK_FREQ(SYS_CLK_FREQ), .BAUD_RATE(BAUD_RATE) ) u_baud_gen ( .clk(SYS_CLK), .rst_n(RST_N), .baud_clk_16x(baud_clk_16x) ); // 2. 例化UART收发器 UART_Transceiver #( .SYS_CLK_FREQ(SYS_CLK_FREQ), .BAUD_RATE(BAUD_RATE) ) u_uart ( .clk(SYS_CLK), .rst_n(RST_N), .uart_rx(UART_RX), .rx_done(uart_rx_done), .rx_data(uart_rx_data), .tx_en(uart_tx_en), .tx_data(uart_tx_data), .uart_tx(UART_TX), .tx_busy(uart_tx_busy) ); // 3. 例化命令缓冲区 CmdFIFO u_cmd_fifo ( .clk(SYS_CLK), .rst_n(RST_N), .wr_en(cmd_fifo_wr_en & ~cmd_fifo_full), .wr_data(cmd_fifo_wr_data), .rd_en(cmd_fifo_rd_en), .rd_data(cmd_fifo_rd_data), .empty(cmd_fifo_empty), .full(cmd_fifo_full) ); // 4. 例化数据FIFO1 SyncFIFO #( .DATA_WIDTH(24), .DEPTH(16), .HALF_DEPTH(8) ) u_fifo1 ( .clk(SYS_CLK), .rst_n(RST_N), .wr_en(fifo1_wr_en), .wr_data(fifo1_wr_data), .rd_en(fifo1_rd_en), .rd_data(fifo1_rd_data), .empty(fifo1_empty), .full(FIFO1_FULL), .half_full(FIFO1_HALF_FULL), .wr_ack(fifo1_wr_ack) ); // 5. 例化数据FIFO2 SyncFIFO #( .DATA_WIDTH(24), .DEPTH(16), .HALF_DEPTH(8) ) u_fifo2 ( .clk(SYS_CLK), .rst_n(RST_N), .wr_en(fifo2_wr_en), .wr_data(fifo2_wr_data), .rd_en(fifo2_rd_en), .rd_data(fifo2_rd_data), .empty(fifo2_empty), .full(FIFO2_FULL), .half_full(FIFO2_HALF_FULL), .wr_ack(fifo2_wr_ack) ); // 6. 命令读取使能(发送空闲且有命令) assign cmd_fifo_rd_en = (tx_state == S_TX_IDLE) && !cmd_fifo_empty; // 7. FIFO读使能(命令有效且发送空闲) assign fifo1_rd_en = (cmd_fifo_rd_data == CMD_READ_FIFO1) && (tx_state == S_TX_IDLE) && !fifo1_empty; assign fifo2_rd_en = (cmd_fifo_rd_data == CMD_READ_FIFO2) && (tx_state == S_TX_IDLE) && !fifo2_empty; // 8. 状态输出映射 assign FPGA_DATA_RDY = !fifo1_empty || !fifo2_empty; assign LATCH1_OVERFLOW = latch1_overflow; assign LATCH2_OVERFLOW = latch2_overflow; assign LATCH2_INVALID_CFG = latch2_invalid_cfg; // 9. 命令处理逻辑(解析命令,填充发送缓冲) always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin tx_data_buf <= 24'd0; cmd_process_done <= 1'b0; STM32_RD_DONE <= 1'b0; end else begin cmd_process_done <= 1'b0; STM32_RD_DONE <= 1'b0; case (cmd_fifo_rd_data) // 读取FIFO1 CMD_READ_FIFO1: begin if (tx_state == S_TX_IDLE && !cmd_fifo_empty) begin if (fifo1_empty) begin tx_data_buf <= DATA_EMPTY; // FIFO空,返回0x000000 end else if (latch1_overflow) begin tx_data_buf <= DATA_OVERFLOW; // 溢出,返回0xFFFFFF end else begin tx_data_buf <= fifo1_rd_data; // 正常数据 end tx_state <= S_TX_HIGH; // 启动发送 end end // 读取FIFO2 CMD_READ_FIFO2: begin if (tx_state == S_TX_IDLE && !cmd_fifo_empty) begin if (fifo2_empty) begin tx_data_buf <= DATA_EMPTY; // FIFO空 end else if (latch2_overflow) begin tx_data_buf <= DATA_OVERFLOW; // 溢出 end else if (latch2_invalid_cfg) begin tx_data_buf <= DATA_INVALID_CFG; // 配置无效 end else begin tx_data_buf <= fifo2_rd_data; // 正常数据 end tx_state <= S_TX_HIGH; // 启动发送 end end // 清除FIFO1 CMD_CLEAR_FIFO1: begin cmd_process_done <= 1'b1; end // 清除FIFO2 CMD_CLEAR_FIFO2: begin cmd_process_done <= 1'b1; end // 清除所有(FIFO+锁存器) CMD_CLEAR_ALL: begin cmd_process_done <= 1'b1; STM32_RD_DONE <= 1'b1; // 通知锁存器清零 end // 无效命令 default: begin if (tx_state == S_TX_IDLE && !cmd_fifo_empty) begin tx_data_buf <= 24'h000000; // 返回空数据 tx_state <= S_TX_HIGH; end end endcase end end // 10. 发送状态机(分3字节发送24位数据) always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin tx_state <= S_TX_IDLE; uart_tx_en <= 1'b0; uart_tx_data <= 8'd0; end else begin uart_tx_en <= 1'b0; case (tx_state) S_TX_IDLE: begin // 命令处理完成或发送结束,回到空闲 end S_TX_HIGH: begin if (!uart_tx_busy) begin uart_tx_en <= 1'b1; uart_tx_data <= tx_data_buf[23:16]; // 发送高8位 tx_state <= S_TX_MID; end end S_TX_MID: begin if (!uart_tx_busy) begin uart_tx_en <= 1'b1; uart_tx_data <= tx_data_buf[15:8]; // 发送中8位 tx_state <= S_TX_LOW; end end S_TX_LOW: begin if (!uart_tx_busy) begin uart_tx_en <= 1'b1; uart_tx_data <= tx_data_buf[7:0]; // 发送低8位 tx_state <= S_TX_IDLE; // 读取命令完成,通知锁存器(仅读取命令) if (cmd_fifo_rd_data == CMD_READ_FIFO1 || cmd_fifo_rd_data == CMD_READ_FIFO2) begin STM32_RD_DONE <= 1'b1; end end end endcase end end // 11. 中断脉冲生成(新数据写入FIFO或溢出时,1周期高脉冲) reg fifo1_empty_prev, fifo2_empty_prev; reg latch1_overflow_prev, latch2_overflow_prev; always @(posedge SYS_CLK or negedge RST_N) begin if (!RST_N) begin fifo1_empty_prev <= 1'b1; fifo2_empty_prev <= 1'b1; latch1_overflow_prev <= 1'b0; latch2_overflow_prev <= 1'b0; FPGA_INT <= 1'b0; end else begin // 新数据写入FIFO(空→非空) wire new_data = (!fifo1_empty && fifo1_empty_prev) || (!fifo2_empty && fifo2_empty_prev); // 新溢出发生(0→1) wire new_overflow = (latch1_overflow && !latch1_overflow_prev) || (latch2_overflow && !latch2_overflow_prev); FPGA_INT <= new_data || new_overflow; // 1周期脉冲 // 更新前态 fifo1_empty_prev <= fifo1_empty; fifo2_empty_prev <= fifo2_empty; latch1_overflow_prev <= latch1_overflow; latch2_overflow_prev <= latch2_overflow; end end endmodule ``` #### 11. UART_Transceiver.v(UART收发器,16倍采样+抗干扰) ```verilog module UART_Transceiver #( parameter SYS_CLK_FREQ = 50_000_000, // 系统时钟频率 parameter BAUD_RATE = 115200 // 波特率 )( input wire clk, // 系统时钟 input wire rst_n, // 低电平复位 input wire uart_rx, // UART接收线 output reg rx_done, // 接收完成标志(1周期) output reg [7:0] rx_data,// 接收数据(8位) input wire tx_en, // 发送使能 input wire [7:0] tx_data,// 发送数据(8位) output reg uart_tx, // UART发送线 output reg tx_busy // 发送忙标志 ); wire baud_clk_16x; // 16倍波特率采样时钟(来自BaudGen) // 接收逻辑内部信号 reg [7:0] rx_buf; // 接收缓冲 reg [3:0] rx_bit_cnt; // 数据位计数(0~7) reg [3:0] rx_sample_cnt; // 采样计数(0~15) reg [1:0] rx_state; // 接收状态机 reg [2:0] start_sample; // 起始位3次采样(抗干扰) localparam RX_IDLE = 2'd0; // 空闲 localparam RX_START = 2'd1; // 起始位 localparam RX_DATA = 2'd2; // 数据位 localparam RX_STOP = 2'd3; // 停止位 // 发送逻辑内部信号 reg [7:0] tx_buf; // 发送缓冲 reg [3:0] tx_bit_cnt; // 数据位计数(0~7) reg [3:0] tx_sample_cnt; // 采样计数(0~15) reg [1:0] tx_state; // 发送状态机 localparam TX_IDLE = 2'd0; // 空闲 localparam TX_START = 2'd1; // 起始位 localparam TX_DATA = 2'd2; // 数据位 localparam TX_STOP = 2'd3; // 停止位 // 例化波特率发生器 UART_BaudGen #( .SYS_CLK_FREQ(SYS_CLK_FREQ), .BAUD_RATE(BAUD_RATE) ) u_baud_gen ( .clk(clk), .rst_n(rst_n), .baud_clk_16x(baud_clk_16x) ); // 接收逻辑(16倍采样,起始位3次采样抗干扰) always @(posedge clk or negedge rst_n) begin if (!rst_n) begin rx_state <= RX_IDLE; rx_done <= 1'b0; rx_data <= 8'd0; rx_buf <= 8'd0; rx_bit_cnt <= 4'd0; rx_sample_cnt <= 4'd0; start_sample <= 3'b000; end else if (baud_clk_16x) begin rx_done <= 1'b0; case (rx_state) RX_IDLE: begin if (!uart_rx) begin // 检测起始位(低电平) rx_state <= RX_START; rx_sample_cnt <= 4'd0; start_sample <= 3'b000; end end RX_START: begin rx_sample_cnt <= rx_sample_cnt + 1'b1; // 起始位3次采样(第5、7、9个采样点) if (rx_sample_cnt == 4'd5 || rx_sample_cnt == 4'd7 || rx_sample_cnt == 4'd9) begin start_sample[rx_sample_cnt[1:0]] <= uart_rx; end else if (rx_sample_cnt == 4'd15) begin // 多数表决(≥2次低电平则确认起始位) if (start_sample[0] + start_sample[1] + start_sample[2] <= 1'b1) begin rx_state <= RX_DATA; rx_bit_cnt <= 4'd0; end else begin rx_state <= RX_IDLE; // 噪声,返回空闲 end rx_sample_cnt <= 4'd0; end end RX_DATA: begin rx_sample_cnt <= rx_sample_cnt + 1'b1; if (rx_sample_cnt == 4'd15) begin // 中间点采样 rx_buf[rx_bit_cnt] <= uart_rx; // 低位优先 rx_bit_cnt <= rx_bit_cnt + 1'b1; rx_sample_cnt <= 4'd0; if (rx_bit_cnt == 4'd7) begin rx_state <= RX_STOP; // 8位数据接收完成 end end end RX_STOP: begin rx_sample_cnt <= rx_sample_cnt + 1'b1; if (rx_sample_cnt == 4'd15) begin // 停止位采样完成 rx_state <= RX_IDLE; rx_done <= 1'b1; rx_data <= rx_buf; // 输出接收数据 end end endcase end end // 发送逻辑(16倍采样同步,低位优先) always @(posedge clk or negedge rst_n) begin if (!rst_n) begin tx_state <= TX_IDLE; uart_tx <= 1'b1; // 空闲高电平 tx_busy <= 1'b0; tx_buf <= 8'd0; tx_bit_cnt <= 4'd0; tx_sample_cnt <= 4'd0; end else if (baud_clk_16x) begin case (tx_state) TX_IDLE: begin uart_tx <= 1'b1; tx_busy <= 1'b0; if (tx_en) begin // 收到发送使能 tx_state <= TX_START; tx_busy <= 1'b1; tx_buf <= tx_data; tx_sample_cnt <= 4'd0; end end TX_START: begin uart_tx <= 1'b0; // 发送起始位(低电平) tx_sample_cnt <= tx_sample_cnt + 1'b1; if (tx_sample_cnt == 4'd15) begin tx_state <= TX_DATA; tx_bit_cnt <= 4'd0; tx_sample_cnt <= 4'd0; end end TX_DATA: begin uart_tx <= tx_buf[tx_bit_cnt]; // 低位优先发送 tx_sample_cnt <= tx_sample_cnt + 1'b1; if (tx_sample_cnt == 4'd15) begin tx_bit_cnt <= tx_bit_cnt + 1'b1; tx_sample_cnt <= 4'd0; if (tx_bit_cnt == 4'd7) begin tx_state <= TX_STOP; // 8位数据发送完成 end end end TX_STOP: begin uart_tx <= 1'b1; // 发送停止位(高电平) tx_sample_cnt <= tx_sample_cnt + 1'b1; if (tx_sample_cnt == 4'd15) begin tx_state <= TX_IDLE; // 发送完成,返回空闲 end end endcase end end endmodule ``` ### 四、顶层模块(模块互联,对外接口) #### 12. Top_UART_FIFO.v(顶层模块,整合所有子模块) ```verilog module Top_UART_FIFO #( parameter SYS_CLK_FREQ = 50_000_000, // 系统时钟频率(50MHz) parameter BAUD_RATE = 115200 // UART波特率 )( // 输入信号 input wire SIGNAL, // 外部传感器输入(异步) input wire SYS_CLK, // 系统时钟 input wire RST_N, // 全局低电平复位(0=复位) input wire [2:0] WHEEL, // 分频配置:001=8,010=16,011=24,100=32,101=40 // UART接口(与STM32通信) input wire UART_RX, // UART接收(来自STM32) output wire UART_TX, // UART发送(给STM32) // 输出状态信号(调试/报警) output wire FPGA_INT, // 中断脉冲(给STM32) output wire FPGA_DATA_RDY, // 数据就绪标志 output wire FIFO1_FULL, // FIFO1满标志 output wire FIFO2_FULL, // FIFO2满标志 output wire FIFO1_HALF_FULL, // FIFO1半满标志 output wire FIFO2_HALF_FULL, // FIFO2半满标志 output wire LATCH1_OVERFLOW, // 锁存器1溢出报警 output wire LATCH2_OVERFLOW, // 锁存器2溢出报警 output wire LATCH2_INVALID_CFG // 锁存器2配置无效报警 ); // 内部互联信号 wire signal_sync; // 传感器信号同步后(无亚稳态) wire div2, div_N; // 2分频/N分频输出 wire div2_rise, div2_fall; // 2分频边沿脉冲 wire div_N_rise, div_N_fall; // N分频边沿脉冲 wire [23:0] latch1_data, latch2_data; // 锁存器数据 wire latch1_valid, latch2_valid; // 锁存器有效标志 wire latch1_overflow, latch2_overflow; // 锁存器溢出标志 wire latch2_invalid_cfg; // 配置无效标志 wire STM32_RD_DONE; // 读取完成(通知锁存器) wire fifo1_wr_ack, fifo2_wr_ack; // FIFO写确认(给锁存器) wire wheel_valid; // 分频配置有效标志 // 1. 异步信号同步(消除亚稳态) SyncTwoStage u_sync_signal( .clk(SYS_CLK), .rst_n(RST_N), .din(SIGNAL), .dout(signal_sync) ); // 2. 分频模块(生成2分频/N分频) Div2Gen u_div2( .SYS_CLK(SYS_CLK), .RST_N(RST_N), .sync_signal(signal_sync), .div2(div2) ); DivNGen u_divN( .SYS_CLK(SYS_CLK), .RST_N(RST_N), .WHEEL(WHEEL), .sync_signal(signal_sync), .div_N(div_N), .wheel_valid(wheel_valid) ); // 3. 边沿检测(生成计数启动/停止脉冲) EdgeDetector u_edg_div2( .SYS_CLK(SYS_CLK), .RST_N(RST_N), .sig_in(div2), .rise(div2_rise), .fall(div2_fall) ); EdgeDetector u_edg_divN( .SYS_CLK(SYS_CLK), .RST_N(RST_N), .sig_in(div_N), .rise(div_N_rise), .fall(div_N_fall) ); // 4. 计数锁存器(计数系统时钟,双缓冲锁存) CntLatch1 u_cnt1( .SYS_CLK(SYS_CLK), .RST_N(RST_N), .STM32_RD_DONE(STM32_RD_DONE), .div2_rise(div2_rise), .div2_fall(div2_fall), .latch1_data(latch1_data), .latch1_valid(latch1_valid), .latch1_overflow(latch1_overflow), .fifo_wr_ack(fifo1_wr_ack) ); CntLatch2 u_cnt2( .SYS_CLK(SYS_CLK), .RST_N(RST_N), .STM32_RD_DONE(STM32_RD_DONE), .div_N_rise(div_N_rise), .div_N_fall(div_N_fall), .wheel_valid(wheel_valid), .latch2_data(latch2_data), .latch2_valid(latch2_valid), .latch2_overflow(latch2_overflow), .latch2_invalid_cfg(latch2_invalid_cfg), .fifo_wr_ack(fifo2_wr_ack) ); // 5. 通信控制模块(UART+FIFO+命令处理) STM32Comm_UART_FIFO #( .SYS_CLK_FREQ(SYS_CLK_FREQ), .BAUD_RATE(BAUD_RATE) ) u_comm( .SYS_CLK(SYS_CLK), .RST_N(RST_N), .latch1_data(latch1_data), .latch1_valid(latch1_valid), .latch1_overflow(latch1_overflow), .latch2_data(latch2_data), .latch2_valid(latch2_valid), .latch2_overflow(latch2_overflow), .latch2_invalid_cfg(latch2_invalid_cfg), .fifo1_wr_ack(fifo1_wr_ack), .fifo2_wr_ack(fifo2_wr_ack), .STM32_RD_DONE(STM32_RD_DONE), .UART_RX(UART_RX), .UART_TX(UART_TX), .FPGA_INT(FPGA_INT), .FPGA_DATA_RDY(FPGA_DATA_RDY), .FIFO1_FULL(FIFO1_FULL), .FIFO2_FULL(FIFO2_FULL), .FIFO1_HALF_FULL(FIFO1_HALF_FULL), .FIFO2_HALF_FULL(FIFO2_HALF_FULL), .LATCH1_OVERFLOW(LATCH1_OVERFLOW), .LATCH2_OVERFLOW(LATCH2_OVERFLOW), .LATCH2_INVALID_CFG(LATCH2_INVALID_CFG) ); endmodule ```
11-29
Nano-ESG数据资源库的构建基于2023年初至2024年秋季期间采集的逾84万条新闻文本,从中系统提炼出企业环境、社会及治理维度的信息。其构建流程首先依据特定术语在德语与英语新闻平台上检索,初步锁定与德国DAX 40成分股企业相关联的报道。随后借助嵌入技术对文本段落执行去重操作,以降低内容冗余。继而采用GLiNER这一跨语言零样本实体识别系统,排除与目标企业无关的文档。在此基础上,通过GPT-3.5与GPT-4o等大规模语言模型对文本进行双重筛选:一方面判定其与ESG议题的相关性,另一方面生成简明的内容概要。最终环节由GPT-4o模型完成,它对每篇文献进行ESG情感倾向(正面、中性或负面)的判定,并标注所涉及的ESG具体维度,从而形成具备时序特征的ESG情感与维度标注数据集。 该数据集适用于多类企业可持续性研究,例如ESG情感趋势分析、ESG维度细分类别研究,以及企业可持续性事件的时序演变追踪。研究者可利用数据集内提供的新闻摘要、情感标签与维度分类,深入考察企业在不同时期的环境、社会及治理表现。此外,借助Bertopic等主题建模方法,能够从数据中识别出与企业相关的核心ESG议题,并观察这些议题随时间的演进轨迹。该资源以其开放获取特性与连续的时间覆盖,为探究企业可持续性表现的动态变化提供了系统化的数据基础。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
Redmi/diting/diting:15/AQ3A.241006.001/OS2.0.206.0.VLFCNXM:user/release-keys #00 pc 0000000000c4eb5c /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (VisualEffect::UpdateRenderer()+72) (BuildId: 12a2cf113d366ee9) #01 pc 0000000000c4f688 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (VisualEffect::AwakeFromLoad(AwakeFromLoadMode)+100) (BuildId: 12a2cf113d366ee9) #02 pc 00000000008bbb8c /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (AwakeFromLoadQueue::InvokePersistentManagerAwake(AwakeFromLoadQueue::Item*, unsigned int, AwakeFromLoadMode, bool)+352) (BuildId: 12a2cf113d366ee9) #03 pc 00000000008bb990 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (AwakeFromLoadQueue::PersistentManagerSingleQueueAwakeFromLoad(int, AwakeFromLoadMode)+136) (BuildId: 12a2cf113d366ee9) #04 pc 00000000008bb8ec /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (AwakeFromLoadQueue::PersistentManagerAwakeFromLoad_NoChecks(AwakeFromLoadMode)+28) (BuildId: 12a2cf113d366ee9) #05 pc 00000000007060a4 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (LoadSceneOperation::CompleteAwakeSequence()+216) (BuildId: 12a2cf113d366ee9) #06 pc 0000000000705cd4 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (LoadSceneOperation::PostLoadSceneAdditive()+24) (BuildId: 12a2cf113d366ee9) #07 pc 0000000000705bec /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (LoadSceneOperation::IntegrateMainThread()+140) (BuildId: 12a2cf113d366ee9) #08 pc 0000000000706b0c /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (PreloadManager::UpdatePreloadingSingleStep(PreloadManager::UpdatePreloadingFlags, int)+280) (BuildId: 12a2cf113d366ee9) #09 pc 0000000000707754 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (PreloadManager::UpdatePreloading()+284) (BuildId: 12a2cf113d366ee9) #10 pc 00000000006e7c80 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (BuildId: 12a2cf113d366ee9) #11 pc 00000000006db4d4 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (ExecutePlayerLoop(NativePlayerLoopSystem*)+132) (BuildId: 12a2cf113d366ee9) #12 pc 00000000006db514 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (ExecutePlayerLoop(NativePlayerLoopSystem*)+196) (BuildId: 12a2cf113d366ee9) #13 pc 00000000006db82c /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (PlayerLoop()+324) (BuildId: 12a2cf113d366ee9) #14 pc 000000000091c454 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (UnityPlayerLoop()+836) (BuildId: 12a2cf113d366ee9) #15 pc 000000000093b044 /data/app/~~HMeIanM_7-GS2f7Bqw4VCA==/com.PrankishCutieAtelier.PetiteElixirAdept-04Ij53qMszdL2UOXRv1XpQ==/lib/arm64/libunity.so (nativeRender(_JNIEnv*, _jobject*)+84) (BuildId: 12a2cf113d366ee9) #16 pc 0000000000226f70 /apex/com.android.art/lib64/libart.so (art_quick_generic_jni_trampoline+144) (BuildId: 72b46491efe77f7340a222a3a1f3c8fb) #17 pc 0000000000210774 /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+612) (BuildId: 72b46491efe77f7340a222a3a1f3c8fb) #18 pc 0000000000472028 /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+160) (BuildId: 72b46491efe77f7340a222a3a1f3c8fb) #19 pc 00000000005dff5c /apex/com.android.art/lib64/libart.so (bool art::interpreter::D 崩溃错误 判定一下是因为什么导致崩溃
10-21
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值