CF 242E XOR on Segment

本文介绍了一种利用线段树解决数组区间异或更新与查询求和问题的方法。通过维护每一位上1的数量,实现了高效处理两种操作:查询指定区间的元素之和与将指定区间内所有元素与特定值进行异或运算。

题目链接:http://codeforces.com/problemset/problem/242/E


题目大意:

给定一个长为n(n<=10^5)的数组,数组里的数不超过10^6,有两种操作

1:求sum[l,r];       2:对[l,r]中的所有数和x异或


题目思路:

一看题目,摆明了是成段更新的线段树,但是异或不符合分配律的( (a+b)^x != a^x+b^x ) ,但是我们知道异或对于一个数上的二进制表达式的所有位是独立的,又知道数组中的数不超过10^6,二进制大概是20位,所以我们线段树就维护该段中所有数的某一位上有几个1和0即可.


代码:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <math.h>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define ll long long
#define ls rt<<1
#define rs ls|1
#define lson l,mid,ls
#define rson mid+1,r,rs
#define middle (l+r)>>1
#define eps (1e-9)
#define type int
#define clr_all(x,c) memset(x,c,sizeof(x))
#define clr(x,c,n) memset(x,c,sizeof(x[0])*(n+1))
#define MOD 1000000007
#define inf 0x3f3f3f3f
#define pi acos(-1.0)
#define _max(x,y) (((x)>(y))? (x):(y))
#define _min(x,y) (((x)<(y))? (x):(y))
#define _abs(x) ((x)<0? (-(x)):(x))
#define getmin(x,y) (x= (x==-1 || (y)<x)? (y):x)
#define getmax(x,y) (x= ((y)>x)? (y):x)
template <class T> void _swap(T &x,T &y){T t=x;x=y;y=t;}
int TS,cas;
const int M=100000+5;

int n,m;
int sum[M<<2][20][2],cov[M<<2],ret[20];

void pushUp(int rt){
	for(int i=0;i<20;i++)
		for(int j=0;j<2;j++)
			sum[rt][i][j]=sum[ls][i][j]+sum[rs][i][j];
}

void build(int l,int r,int rt){
	if(l==r){
		int a;
		scanf("%d",&a);
		clr_all(sum[rt],0),cov[rt]=0;
		for(int i=0;i<20;i++,a/=2)
			sum[rt][i][a&1]++;
		return;
	}
	int mid=middle;
	build(lson),build(rson);
	pushUp(rt);
}

void pushDown(int rt){
	if(!cov[rt]) return;
	cov[ls]^=cov[rt],cov[rs]^=cov[rt];
	for(int i=0;cov[rt];i++,cov[rt]/=2) if(cov[rt]&1){
		_swap(sum[ls][i][0],sum[ls][i][1]);
		_swap(sum[rs][i][0],sum[rs][i][1]);
	}
}

void update(int l,int r,int rt,int L,int R,int c){
	if(L<=l && r<=R){
		cov[rt]^=c;
		int i;
		for(i=0;c;i++,c/=2) if(c&1)
			_swap(sum[rt][i][0],sum[rt][i][1]);
		return;
	}
	pushDown(rt);
	int mid=middle;
	if(L<=mid) update(lson,L,R,c);
	if(mid<R) update(rson,L,R,c);
	pushUp(rt);
}

void query(int l,int r,int rt,int L,int R){
	if(L<=l && r<=R){
		for(int i=0;i<20;i++)
			ret[i]+=sum[rt][i][1];
		return;
	}
	pushDown(rt);
	int mid=middle;
	if(L<=mid) query(lson,L,R);
	if(mid<R) query(rson,L,R);
}

void run(){
	int i,j;
	build(1,n,1);
	scanf("%d",&m);
	int t,l,r,x;
	while(m--){
		scanf("%d%d%d",&t,&l,&r);
		if(t==1){
			clr_all(ret,0);
			query(1,n,1,l,r);
			ll ans=0,g=0,pw2=1,c;
			for(i=0;i<20 || g;i++,pw2*=2){
				c=g+((i<20)? ll(ret[i]):0);
				ans+=(c%2)*pw2;
				g=c/2;
			}
			printf("%I64d\n",ans);
		}else{
			scanf("%d",&x);
			update(1,n,1,l,r,x);
		}
	}
}

void preSof(){
}

int main(){
	//freopen("input.txt","r",stdin);
	//freopen("output.txt","w",stdout);
	preSof();
	//run();
	while(~scanf("%d",&n)) run();
	//for(scanf("%d",&TS),cas=1;cas<=TS;cas++) run();
	return 0;
}


以下代码在IDE 仿真时,HUE 编译没有通过,请推理逻辑并加以修正,其中,RF 中断处理程序已经通过实际测试,不能修改,其他部份请重新推理逻辑,编写一个完整的代码给出可以吗?====//*******product model:RGB 彩灯 .CHIP PMS132B ;SOP16 //.CHIP PFC154 ;SOP14 //.CHIP PMC153 ;SOP14 //{{PADAUK_CODE_OPTION .Code_Option LVR 3.5V .Code_Option Security Enable // Security 7/8 words Enable .Code_Option Comparator_Edge All_Edge .Code_Option Bootup_Time Slow .Code_Option PWM_Source 16MHz .Code_Option GPC_PWM Disable .Code_Option Interrupt_Src1 PB.0 .Code_Option Interrupt_Src0 PA.0 .Code_Option PB4_PB7_Drive Strong //}}PADAUK_CODE_OPTION .INCLUDE "HEAD.H" ;----------- 常量定义 ----------- SYNC_MIN EQU 32 ; 同步头最小(8ms) SYNC_MAX EQU 56 ; 同步头最大(14ms) DATA_0_MIN EQU 1 ; 数据0最小(0.2ms) DATA_0_MAX EQU 2 ; 数据0最大(0.6ms) DATA_1_MIN EQU 3 ; 数据1最小(0.8ms) DATA_1_MAX EQU 5 ; 数据1最大(1.4ms) RF EQU PA.0 ;RF_IN_Size => 3 ;MAX_BRIGHTNESS EQU 6 ;6级亮度 ;********************************************************* .ROMADR 0X001 ;; GOTO FPPA0 ;******************************************************** .ROMADR 0X10 ;INTERR IN address ;====================== 中断服务程序 ====================== INTERRUPT: PUSHAF ; 保存现场 T1SN INTRQ.2;T16 GOTO TM2_INT ;------------------------------------------- TM16_INT: SET0 INTRQ.2 ; 处理T16中断 INC T16_TIEMS_COUNTER_TIME_R ; 每次进入中断时,递增一个计时器变量,用于累计时间 ; 检查是否达到40ms MOV A, T16_TIEMS_COUNTER_TIME_R ; 将计时器值加载到累加器A中 CEQSN A, 40 ; 如果A等于40,则跳转到UPDATE_GRADIENT执行颜色更新逻辑 GOTO ISR_EXIT; ; 否则直接退出中断 GOTO UPDATE_GRADIENT UPDATE_GRADIENT: ; 更新渐变步进 INC STEP_A ; 增加STEP_A,表示A路LED的色相步进 DZSN STEP_A;, RESET_STEP_A ; 如果STEP_A溢出(即超过255),则跳转到RESET_STEP_A重置为0 GOTO $+2 GOTO RESET_STEP_A INC STEP_B ; 增加STEP_B,表示B路LED的色相步进 DZSN STEP_B;, RESET_STEP_B ; 如果STEP_B溢出(即超过255),则跳转到RESET_STEP_B重置为0 GOTO ISR_EXIT GOTO RESET_STEP_B ; 跳回中断退出点 RESET_STEP_A: MOV A,0 MOV STEP_A,A; 0; ; 将STEP_A重置为0,重新开始下一个颜色循环 GOTO ISR_EXIT; ; 返回中断退出点 RESET_STEP_B: MOV A,0 MOV STEP_B,A; 0; ; 将STEP_B重置为0,重新开始下一个颜色循环 GOTO ISR_EXIT; ; 返回中断退出点 ;------------------------------------------ TM2_INT: ; TM2中断处理 (250us周期) T1SN INTRQ.TM2 ; 检测TM2中断标志 GOTO CHECK_RF ;PA0 中断检查 INC Timer_250us ; 专用TM2计数器 SET0 INTRQ.TM2 ; 清除中断标志 MOV A, 72;80;Timer_250us ; 加载计数器值 SUB A, Timer_250us ; 18ms超时检测 T1SN FC ; 检查是否超时 GOTO ISR_Exit ; 未超时继续 SET0 RF_Start ; 超时复位接收状态 CLEAR Timer_250us ; 重置计时器 GOTO ISR_Exit; CHECK_RF: T1SN INTRQ. RF ; 检测RF中断标志 GOTO ISR_Exit ;ISR_END T1SN PA.0 ; 检测PA0当前电平(1=高电平) GOTO RF_Clear;RF_Low ; 低电平处理分支 T1SN RF_Start ; 检查是否已经开始接收 GOTO Check_Start ; 起始码检测分支 ; 数据位 ;------ 1码检测-------------------- ;----- 0:----0.3ms-0.6mS H + 0.8mS-1.4ms L ;------1:----0.8-1.4ms H + 0.3-1.4ms L ;结束位:-----0.3-0.6ms H + 10-14ms L ;(Timer_250us>=3 && Timer_250us<=5) //0.75~1.25ms INC Icnt ; 位计数器加1 MOV A, Timer_250us ; 加载计时器值 SUB A,DATA_1_MIN; 3 ; 1码检测下限(0.75ms) T0SN FC ; 检查是否大于下限 GOTO Check_Zero ; 跳转0码检测 MOV A,DATA_1_MAX; 5 ; 1码检测上限(1.25ms) SUB A, Timer_250us ; 计算时间差 T0SN FC ; 检查是否小于上限 GOTO Check_Zero ; 跳转0码检测 SET0 CF ; 设置进位标志为1 SLC Data_In$0 ; 数据左移并带进位 SLC Data_In$1 ; 数据左移并带进位 SLC Data_In$2 ; 数据左移并带进位 GOTO Check_Complete ; 跳转完成检测 Check_Zero: ; ------0码检测------- ;(Timer_250us>=1 && Timer_250us<=2)//0.25~0.5ms MOV A, Timer_250us ; 加载计时器值 SUB A,DATA_0_MIN; 1 ; 0码下限(0.25ms) T0SN FC ; 检查是否大于下限 GOTO Data_Error ; 错误处理 MOV A,DATA_0_MAX; 2 ; 0码上限(0.5ms) SUB A, Timer_250us ; 计算时间差 T0SN FC ; 检查是否小于上限 GOTO Data_Error ; 错误处理 SET1 FC ; 设置进位标志为0 SLC Data_In$0 ; 数据左移并带进位 SLC Data_In$1 ; 数据左移并带进位 SLC Data_In$2 ; 数据左移并带进位 Check_Complete: ; 完成检测 MOV A, 24 ; 加载位计数器 XOR A, Icnt ; 检查是否满24位 T1SN FZ ; 判断是否完成 GOTO RF_Clear ; 未完成继续接收 ; SET1 RF_End ; 设置接收完成标志 SET0 RF_Start ; 清除接收开始标志 ; 数据存储与校验 current_RF_ID_R0 = Data_In$0; ;.0-7 ; 存储低8位 current_RF_ID_R1 = Data_In$1; current_RF_ID_R2 = Data_In$2; T0SN FIRST_ID_SVAE_FLAG GOTO SVAE_ID ; DTAT_SAVE_R0=current_RF_ID_R0; DTAT_SAVE_R1=current_RF_ID_R1; DTAT_SAVE_R2=current_RF_ID_R2; SET1 FIRST_ID_SVAE_FLAG SVAE_ID: SET1 RF_END GOTO RF_Clear ; 跳转中断清除 Check_Start: ; 起始码检测 ;----(Timer_250us>=32 && Timer_250us<=48) //用8-12ms低电平做起始码 MOV A, Timer_250us ; 加载计时器值 SUB A,SYNC_MIN; 32 ; 起始码下限(8.75ms) T0SN FC ; 检查是否大于下限 GOTO RF_Clear ; 无效起始码 MOV A,SYNC_MAX; 56;48 ; 起始码上限(11.25ms) SUB A, Timer_250us ; 计算时间差 T0SN FC ; 检查是否小于上限 GOTO RF_Clear ; 无效起始码 SET1 RF_Start ; 设置接收开始标志 Data_In = 0 ; ; 清空数据缓存 CLEAR Icnt ; 复位位计数器 CLEAR Timer_250us ; 重置250us计时器 GOTO RF_Clear Data_Error: ; 错误处理 CLEAR Icnt ; 复位位计数器 SET0 RF_Start ; 清除接收开始标志 Data_In = 0 ; ; 清空数据缓存 CLEAR Timer_250us ; 重置250us计时器 RF_Clear: ; RF中断清除 SET0 INTRQ.RF ; 清除RF中断标志 CLEAR Timer_250us ; 重置250us计时器 GOTO ISR_Exit ; 跳转中断退出 TM2_Clear: ; 定时器中断清除 SET0 INTRQ.TM2 ; 清除定时器中断标志 GOTO ISR_EXIT ISR_Exit: ; 中断退出 POPAF ; 恢复A和FLAG寄存器 RETI ; 中断返回 ;-------------------------------------------- //======================================================= FPPA0: .ADJUST_IC SYSCLK=IHRC/4, IHRC=16MHz, VDD=5.0V; // WatchDog Disable, RAM 0 ~ 0xF temporary be used //You can add the follow code : CLKMD.En_WatchDog=0; // WatchDog Enable SP=STACK0 ;//--------------CLRRAM ---------------------- Initialize: ; CALL DELAY_1SUP; MOV A,_SYS(RAM_SIZE)-1 MOV LB@RAM_POINTER,A CLEAR HB@RAM_POINTER L_CLRRAMLP: MOV A,0X00 IDXM RAM_POINTER,A DZSN LB@RAM_POINTER GOTO L_CLRRAMLP ;//--------------INITIAL IO---------------------- IO_Initialize: PA = 0B_0000_1000; PAC = 0B_0111_1000; ; //0:input;1:output; PAPH = 0B_1111_1001; ;1=ENABLED PULL UP PADIER=0B_1111_1111; PB=0B_1000_0000; PBC=0B_0111_1001; ; //0:input;1:output; PBPH=0B_1111_1001; ;1=ENABLED PULL UP PBDIER=0B_1111_1111; ;--------TM2 250uS ------------------- TM2CT=0; ; 清零定时器计数器 MOV A,9 MOV TM2B, A ; 设置预分频值为9 $ TM2C IHRC,Period ; 配置时钟源为内部高速RC $ TM2S 8BIT,/16,/25 ; 设置8位模式,16分频,25周期 SET0 INTRQ.TM2; ; 清除定时器中断标志 SET1 INTEN.TM2; ; 使能定时器中断 ;-----------PA0 IN_INT --------------------------- //设置PA0引脚输入模式,根据情况选择是否需要上拉 $ PA.0 in,pull; $ INTEGS PA0_B; //PA0中断边缘选择,上升缘和下降缘上升缘都请求中断PA0_B,上升缘请求中断为PA0_R,下降缘请求中断为PA0_F。 SET1 INTEN.PA0; = 1; //中断允许寄存器,开PA0中断 SET0 INTRQ.PA0; = 0; //中断请求寄存器,清零INTRQ寄存器。 ;-------------1MS--------------------------------------- Reload_T16 = 32768 - 16000; stt16 Reload_T16; $ T16M IHRC,/1,bit15; $ INTEGS BIT_R; INTRQ.T16 = 0; INTEN.T16 = 1; Engint; ;************************************************************* START: MOV A,0 ; 清除累加器 A SET1 POWER_RUN_FALG; 设置初始状态为开启 MOV A,7 MOV CUR_MODE,A; 7 ; 设置当前模式为7 MOV A,3 MOV BRIGHT_LEVEL,A; 3 ; 设置初始亮度等级为中间值 ;------------PWMG1------------------------------------- $ PWMG1C Enable,PA4,IHRC; $ PWMG1S /4,/1; PWMG1DTL = 0b010_00000; PWMG1DTH = 0b0100_0111; PWMG1CUBL = 0b10_000000; PWMG1CUBH = 0b1000_1110; ;------------PWMG2------------------------------------- $ PWMG2C Enable,PB3,IHRC; $ PWMG2S /4,/1; PWMG2DTL = 0b010_00000; PWMG2DTH = 0b0100_0111; PWMG2CUBL = 0b10_000000; PWMG2CUBH = 0b1000_1110; ; 初始化定时器 T16 CLEAR T16_TIEMS_COUNTER_TIME_R; 清除计时器 GOTO MAIN; 跳转到主循环 ;暖白-红-绿-蓝-紫-青-粉-白光-黄光 MAIN: CALL COMPLETE_RF_ID CALL Power_Control_ON_OFF CALL MODE_DECIDE NOP GOTO MAIN ;***************************************************************** COMPLETE_RF_ID: T1SN RF_End ; 设置接收完成标志 RET current_ID_COMPLETE: MOV A,current_RF_ID_R1; CEQSN A,DTAT_SAVE_R1 GOTO ID_EEROR MOV A,current_RF_ID_R2 CEQSN A,DTAT_SAVE_R2 RET SET1 ID_COMPLETE_OK_FLAG;ID 正确 SET0 RF_End ; 设置接收完成标志 current_RF_ID_R0 = Data_In$0; RET ID_EEROR: SET0 ID_COMPLETE_OK_FLAG;ID 正确 SET0 RF_End ; 设置接收完成标志 RET ;**************************************************************** Power_Control_ON_OFF: ; CEQSN A, 2, POWER_TOGGLE; 如果等于 02H,则跳转到电源切换函数 MOV A,02H ; 将按键值加载到ACC中 XOR A,current_RF_ID_R0 ; 检查是否为02H(开/关机) T1SN FZ RET T0SN POWER_RUN_FALG GOTO POWER_OFF GOTO Power_Control_ON POWER_OFF: SET0 POWER_RUN_FALG ; GOTO Power_Control_OFF Power_Control_OFF: ;关闭全部PWM MOV A, 0 MOV Duty_R_RGB_A, A MOV Duty_G_RGB_A, A MOV Duty_B_RGB_A, A MOV Duty_R_RGB_B, A MOV Duty_G_RGB_B, A MOV Duty_B_RGB_B, A RET Power_Control_ON: ; MOV A, DTAT_SAVE_R0 ; CEQSN A, 0x02 ; GOTO CHK_04H ; 02H: 开/关机切换 ; XOR POWER_ON_FLAG, 1 T1SN POWER_RUN_FALG CALL UPDATE_MODE ; 开机时更新模式 GOTO Power_Control_OFF RET ;**************************************************************** MODE_DECIDE: ;CEQSN A, 4, INCREASE_BRIGHTNESS; 如果等于 04H,则增加亮度 MOV A, 04H ; 检查是否为04H(亮度增加) CEQSN A,current_RF_ID_R0 GOTO $+2 GOTO Brightness_Up_Handler ; 如果是04H,跳转到亮度增加处理 ;CEQSN A, 10, DECREASE_BRIGHTNESS; 如果等于 0AH,则减少亮度 MOV A,0AH CEQSN A,current_RF_ID_R0 GOTO $+2 GOTO Brightness_Down_Handler ; CEQSN A, 6, NEXT_MODE; 如果等于 06H,则进入下一个模式 MOV A,06H CEQSN A,current_RF_ID_R0 GOTO $+2 GOTO NEXT_MODE ; CEQSN A, 12, PREV_MODE; 如果等于 0CH,则进入上一个模式 MOV A,0CH CEQSN A,current_RF_ID_R0 GOTO $+2 GOTO PREV_MODE ; 如果没有按键操作,继续执行当前模式 GOTO UPDATE_PWM; POWER_TOGGLE: ; 切换电源状态 T1SN POWER_RUN_FALG; POWER_ON_FLAG, 1; 反转电源标志 GOTO MAIN;_LOOP; RET ;***************************************** Brightness_Up_Handler: ; 增加亮度等级 INC BRIGHT_LEVEL ; DZSN BRIGHT_LEVEL, MAX_BRIGHTNESS; 如果超过最大值,回到最小值 ; GOTO UPDATE_PWM; MOV A,5 SUB A,BRIGHT_LEVEL T1SN FC GOTO UPDATE_PWM; ;DECREASE_BRIGHTNESS: Brightness_Down_Handler: ; 减少亮度等级 DEC BRIGHT_LEVEL ; DZSN BRIGHT_LEVEL, MIN_BRIGHTNESS; 如果低于最小值,回到最大值 ; GOTO UPDATE_PWM; MOV A,0 CEQSN A,BRIGHT_LEVEL GOTO UPDATE_PWM; GOTO Brightness_Up_Handler ;--------------切换模式-------------------- NEXT_MODE: ; 切换到下一个模式 INC CUR_MODE ; DZSN CUR_MODE, MAX_MODE; 如果超过最大模式,回到第一个模式 ; GOTO UPDATE_PWM; MOV A,7 SUB A,CUR_MODE T1SN FC GOTO UPDATE_PWM; GOTO PREV_MODE PREV_MODE: ; 切换到上一个模式 ; DEC CUR_MODE ; DZSN CUR_MODE, MIN_MODE; 如果低于最小模式,回到最后一个模式 ; GOTO UPDATE_PWM; DZSN CUR_MODE;, MIN_MODE; 如果低于最小模式,回到最后一个模式 GOTO UPDATE_PWM; GOTO NEXT_MODE ;-------亮度调整----------- ;MAX_BRIGHTNESS: ; MOV BRIGHT_LEVEL, 6; 最大亮度等级 ; GOTO UPDATE_PWM; ;MIN_BRIGHTNESS: ; MOV BRIGHT_LEVEL, 1; 最小亮度等级 ; GOTO UPDATE_PWM; ;MAX_MODE: ; MOV CUR_MODE, 1; 最大模式 ; GOTO UPDATE_PWM; ;MIN_MODE: ; MOV CUR_MODE, 7; 最小模式 ; GOTO UPDATE_PWM; ;****************************************************************** UPDATE_PWM: ; 根据当前模式更新PWM占空比 ; MOV A, CUR_MODE ; CEQSN A, 1, MODE_1; 模式1 ; CEQSN A, 2, MODE_2; 模式2 ; CEQSN A, 3, MODE_3; 模式3 ; CEQSN A, 4, MODE_4; 模式4 ; CEQSN A, 5, MODE_5; 模式5 ; CEQSN A, 6, MODE_6; 模式6 ; CEQSN A, 7, MODE_7; 模式7 MOV A,0 CEQSN A,CUR_MODE GOTO $+2 GOTO MODE_1 MOV A,1 CEQSN A,CUR_MODE GOTO $+2 GOTO MODE_2 MOV A,2 CEQSN A,CUR_MODE GOTO $+2 GOTO MODE_3 MOV A,3 CEQSN A,CUR_MODE GOTO $+2 GOTO MODE_4 MOV A,4 CEQSN A,CUR_MODE GOTO $+2 GOTO MODE_5 MOV A,5 CEQSN A,CUR_MODE GOTO $+2 GOTO MODE_6 MOV A,6 CEQSN A,CUR_MODE GOTO $+2 GOTO MODE_7 ;****************************************************************** ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; UPDATE_MODE: ; 关机时不更新模式 T0SN POWER_RUN_FALG T0SN FZ RET MODE_1: ; 模式1:A路红色,B路绿色 CALL GET_BRIGHTNESS; 获取当前亮度值 MOV Duty_R_RGB_A, A; A路红色 MOV A, 0; A路绿色 MOV Duty_G_RGB_A, A MOV A, 0; A路蓝色 MOV Duty_B_RGB_A, A MOV A, 0; B路红色 MOV Duty_R_RGB_B, A MOV Duty_G_RGB_B, A; B路绿色 MOV A, 0; B路蓝色 MOV Duty_B_RGB_B, A GOTO END_UPDATE; MODE_2: ; 模式2:A路粉色,B路黄色 CALL GET_BRIGHTNESS; 获取当前亮度值 MOV Duty_R_RGB_A, A; A路红色 MOV A, 128; A路绿色 MOV Duty_G_RGB_A, A MOV A, 0; A路蓝色 MOV Duty_B_RGB_A, A MOV A, 128; B路红色 MOV Duty_R_RGB_B, A MOV Duty_G_RGB_B, A; B路绿色 MOV A, 128; B路蓝色 MOV Duty_B_RGB_B, A GOTO END_UPDATE; MODE_3: ; 模式3:A路绿色,B路蓝色 CALL GET_BRIGHTNESS; 获取当前亮度值 MOV A, 0; A路红色 MOV Duty_R_RGB_A, A MOV Duty_G_RGB_A, A; A路绿色 MOV A, 0; A路蓝色 MOV Duty_B_RGB_A, A MOV A, 0; B路红色 MOV Duty_R_RGB_B, A MOV A, 0; B路绿色 MOV Duty_G_RGB_B, A MOV Duty_B_RGB_B, A; B路蓝色 GOTO END_UPDATE; MODE_4: ; 模式4:A路紫色,B路白色 CALL GET_BRIGHTNESS; 获取当前亮度值 MOV Duty_R_RGB_A, A; A路红色 MOV A, 0; A路绿色 MOV Duty_G_RGB_A, A MOV Duty_B_RGB_A, A; A路蓝色 MOV Duty_R_RGB_B, A; B路红色 MOV Duty_G_RGB_B, A; B路绿色 MOV Duty_B_RGB_B, A; B路蓝色 GOTO END_UPDATE; MODE_5: ; 模式5:A路蓝色,B路粉色 CALL GET_BRIGHTNESS; 获取当前亮度值 MOV A, 0; A路红色 MOV Duty_R_RGB_A, A MOV A, 0; A路绿色 MOV Duty_G_RGB_A, A MOV Duty_B_RGB_A, A; A路蓝色 MOV Duty_R_RGB_B, A; B路红色 MOV Duty_G_RGB_B, A; B路绿色 MOV A, 128; B路蓝色 MOV Duty_B_RGB_B, A GOTO END_UPDATE; MODE_6: ; 模ode6:A路蓝色,B路橙色 CALL GET_BRIGHTNESS; 获取当前亮度值 MOV A, 0; A路红色 MOV Duty_R_RGB_A, A MOV A, 0; A路绿色 MOV Duty_G_RGB_A, A MOV Duty_B_RGB_A, A; A路蓝色 MOV Duty_R_RGB_B, A; B路红色 MOV Duty_G_RGB_B, A; B路绿色 MOV A, 128; B路蓝色 MOV Duty_B_RGB_B, A GOTO END_UPDATE; ;************************************************************* END_UPDATE: ; 更新PWM占空比 MOV A,Duty_R_RGB_A; 更新A路红色PWM MOV PWMG2DTL,A MOV A,Duty_R_RGB_A; MOV PWMG2DTH,A MOV A,Duty_G_RGB_A; 更新A路绿色PWM MOV PWMG1DTL,A MOV A,Duty_G_RGB_A; MOV PWMG1DTH,A ; 这里需要添加B路PWM的更新代码 GOTO MAIN ;_LOOP; ;************************************************************ GET_BRIGHTNESS: ; 获取当前亮度值 ; MOV A, BRIGHT_LEVEL ; MOV PC, BRIGHT_TABLE; 查找亮度表 ; RET; A = BRIGHT_LEVEL+1 _PCADD { RET 51; 20%, RET 89; 35%, RET 128; 50%, RET 166; 65%, RET 204; 80%, RET 255; 100%, } ;************************************************************* MODE_7: ; 更新A路颜色 ; 更新A路颜色 MOV A, HUE_A ; 将当前A路色相值加载到累加器A CALL HSV_TO_RGB ; 调用HSV转RGB子程序,得到R、G、B三通道值(R_VAL, G_VAL, B_VAL) CALL GET_BRIGHTNESS ; 获取当前亮度值(存入A) ; 计算红色通道 × 亮度值 MOV A, R_VAL ; 第一个乘数 → A MOV MULOP, A ; 复制A中的值到 MULOP MOV A, BRIGHT ; 第二个乘数 → A MUL ; 执行乘法:R_VAL × BRIGHT MOV Duty_R_RGB_A, A ; 存低字节到PWM寄存器 MOV A, MULRH ; 读取高字节 MOV Duty_R_RGB_H_A, A ; 存高字节备用 ; 计算绿色通道 × 亮度值 MOV A, G_VAL ; 第一个乘数 → A MOV MULOP, A ; 复制A中的值到 MULOP MOV A, BRIGHT ; 第二个乘数 → A MUL ; 执行乘法:G_VAL × BRIGHT MOV Duty_G_RGB_A, A ; 存低字节到PWM寄存器 MOV A, MULRH ; 读取高字节 MOV Duty_G_RGB_H_A, A ; 存高字节备用 ; 计算蓝色通道 × 亮度值 MOV A, B_VAL ; 第一个乘数 → A MOV MULOP, A ; 复制A中的值到 MULOP MOV A, BRIGHT ; 第二个乘数 → A MUL ; 执行乘法:B_VAL × BRIGHT MOV Duty_B_RGB_A, A ; 存低字节到PWM寄存器 MOV A, MULRH ; 读取高字节 MOV Duty_B_RGB_H_A, A ; 存高字节备用 ; 更新B路颜色 MOV A, HUE_B ; 将当前B路色相值加载到累加器A CALL HSV_TO_RGB ; 调用HSV转RGB子程序,得到B路的R、G、B值 CALL GET_BRIGHTNESS ; 获取当前亮度值(存入A) ; 计算B路红色通道 × 亮度值 MOV A, R_VAL ; 第一个乘数 → A MOV MULOP, A ; 复制A中的值到 MULOP MOV A, BRIGHT ; 第二个乘数 → A MUL ; 执行乘法:R_VAL × BRIGHT MOV Duty_R_RGB_B, A ; 存低字节到PWM寄存器 MOV A, MULRH ; 读取高字节 MOV Duty_R_RGB_H_B, A ; 存高字节备用 ; 计算B路绿色通道 × 亮度值 MOV A, G_VAL ; 第一个乘数 → A MOV MULOP, A ; 复制A中的值到 MULOP MOV A, BRIGHT ; 第二个乘数 → A MUL ; 执行乘法:G_VAL × BRIGHT MOV Duty_G_RGB_B, A ; 存低字节到PWM寄存器 MOV A, MULRH ; 读取高字节 MOV Duty_G_RGB_H_B, A ; 存高字节备用 ; 计算B路蓝色通道 × 亮度值 MOV A, B_VAL ; 第一个乘数 → A MOV MULOP, A ; 复制A中的值到 MULOP MOV A, BRIGHT ; 第二个乘数 → A MUL ; 执行乘法:B_VAL × BRIGHT MOV Duty_B_RGB_B, A ; 存低字节到PWM寄存器 MOV A, MULRH ; 读取高字节 MOV Duty_B_RGB_H_B, A ; 存高字节备用 RET ;***************************************************** ; ----------------------------- ; 子程序:HSV_TO_RGB ; 功能:将HSV颜色值转换为RGB颜色值 ; 输入:A = 色相值(0-255) ; 输出:R_VAL, G_VAL, B_VAL(8位RGB通道值) ; 说明:本子程序假设饱和度和亮度已为最大值(255),适用于全彩LED控制 ; 特别注意:所有数据传送必须通过累加器 A 完成(无 # 符号) ; ----------------------------- HSV_TO_RGB: ; 将输入的色相值保存到 SEGMENT 寄存器中 MOV A, HUE ; 将当前色相值加载到 A MOV SEGMENT, A ; 将 A 中的值复制到 SEGMENT ; 右移3位,得到色相区段编号(0~5,共6个区段) ; MOV A, SEGMENT ; 将 SEGMENT 的值加载到 A ; SR A, 3 ; 右移3位,相当于除以8,得到整数部分 SR SEGMENT MOV SEGMENT,A MOV SEGMENT, A ; 将结果存回 SEGMENT ; 计算色相的小数部分 ; MOV A, SEGMENT ; 将整数部分加载到 A ; SL A, 3 ; 左移3位,相当于乘以8,恢复整数部分的8倍 SL SEGMENT MOV FRACTION, A ; 将整数部分的8倍存入 FRACTION MOV A, HUE ; 重新加载原始色相值到 A SUB A, FRACTION ; 原色相值 - 整数部分的8倍 = 小数部分 MOV FRACTION, A ; 将小数部分存入 FRACTION ; 根据区段跳转到对应的RGB计算分支 ; MOV A, SEGMENT ; 将区段编号加载到 A ; CEQSN A, 0, RED_SEGMENT ; 区段0 → 红色区间 MOV A,0 CEQSN A,SEGMENT GOTO $+2 GOTO RED_SEGMENT ; CEQSN A, 1, GREEN_SEGMENT ; 区段1 → 绿色区间 MOV A,1 CEQSN A,SEGMENT GOTO $+2 GOTO GREEN_SEGMENT ; CEQSN A, 2, BLUE_SEGMENT ; 区段2 → 蓝色区间 MOV A,2 CEQSN A,SEGMENT GOTO $+2 GOTO BLUE_SEGMENT ; CEQSN A, 3, MAGENTA_SEGMENT ; 区段3 → 品红区间 MOV A,3 CEQSN A,SEGMENT GOTO $+2 GOTO MAGENTA_SEGMENT ; CEQSN A, 4, CYAN_SEGMENT ; 区段4 → 青色区间 MOV A,4 CEQSN A,SEGMENT GOTO $+2 GOTO CYAN_SEGMENT ; CEQSN A, 5, YELLOW_SEGMENT ; 区段5 → 黄色区间 MOV A,5 CEQSN A,SEGMENT GOTO $+2 GOTO YELLOW_SEGMENT ; 区段0 - 红色区间 (Red to Yellow) RED_SEGMENT: MOV A, 255 ; 加载红色通道最大值 255 到 A MOV R_VAL, A ; 将 A 中的值写入 R_VAL(红色通道满) MOV A, FRACTION ; 将小数部分加载到 A MOV G_VAL, A ; 将 A 中的值写入 G_VAL(绿色通道从小到大变化) MOV A, 0 ; 加载蓝色通道最小值 0 到 A MOV B_VAL, A ; 将 A 中的值写入 B_VAL(蓝色通道不变) RET ; 返回主程序 ; 区段1 - 绿色区间 (Green to Cyan) GREEN_SEGMENT: MOV A, 255 ; 加载 255 到 A SUB A, FRACTION ; A = 255 - FRACTION(红色通道从255递减) MOV R_VAL, A ; 将结果写入 R_VAL MOV A, 255 ; 加载 255 到 A MOV G_VAL, A ; 将 A 中的值写入 G_VAL(绿色通道满) MOV A, 0 ; 加载 0 到 A MOV B_VAL, A ; 将 A 中的值写入 B_VAL(蓝色通道不变) RET ; 返回主程序 ; 区段2 - 蓝色区间 (Blue to Magenta) BLUE_SEGMENT: MOV A, 0 ; 加载 0 到 A MOV R_VAL, A ; 将 A 中的值写入 R_VAL(红色通道不变) MOV A, 255 ; 加载 255 到 A MOV G_VAL, A ; 将 A 中的值写入 G_VAL(绿色通道满) MOV A, FRACTION ; 将小数部分加载到 A MOV B_VAL, A ; 将 A 中的值写入 B_VAL(蓝色通道从小到大变化) RET ; 返回主程序 ; 区段3 - 品红区间 (Magenta to Red) MAGENTA_SEGMENT: MOV A, 0 ; 加载 0 到 A MOV R_VAL, A ; 将 A 中的值写入 R_VAL(红色通道不变) MOV A, 255 ; 加载 255 到 A SUB A, FRACTION ; A = 255 - FRACTION(绿色通道从255递减) MOV G_VAL, A ; 将结果写入 G_VAL MOV A, 255 ; 加载 255 到 A MOV B_VAL, A ; 将 A 中的值写入 B_VAL(蓝色通道满) RET ; 返回主程序 ; 区段4 - 青色区间 (Cyan to Green) CYAN_SEGMENT: MOV A, FRACTION ; 将小数部分加载到 A MOV R_VAL, A ; 将 A 中的值写入 R_VAL(红色通道从小到大变化) MOV A, 0 ; 加载 0 到 A MOV G_VAL, A ; 将 A 中的值写入 G_VAL(绿色通道不变) MOV A, 255 ; 加载 255 到 A MOV B_VAL, A ; 将 A 中的值写入 B_VAL(蓝色通道满) RET ; 返回主程序 ; 区段5 - 黄色区间 (Yellow to Magenta) YELLOW_SEGMENT: MOV A, 255 ; 加载 255 到 A MOV R_VAL, A ; 将 A 中的值写入 R_VAL(红色通道满) MOV A, 0 ; 加载 0 到 A MOV G_VAL, A ; 将 A 中的值写入 G_VAL(绿色通道不变) MOV A, 255 ; 加载 255 到 A SUB A, FRACTION ; A = 255 - FRACTION(蓝色通道从255递减) MOV B_VAL, A ; 将结果写入 B_VAL RET ; 返回主程序
最新发布
09-11
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值