串口全双工通信与串口中断

news2024/11/23 0:52:36

1.串口通信编程

STC-ISP串口助手的使用:

 文本模式和HEX模式的区别:文本模式就是那些可打印的字符。HEX模式就是这些可打印字符对应的16进制。它们都对应相同的ASCII码(用十进制表示)。

  1. 很多小白在程序编写完成后调试时会搞不清楚到底是程序问题还是上位机传送的数据问题,比如在习题3中,到底写成cmd == 1 还是 cmd == '1' 需要简单考虑一下。

代码心得:

  • 当我们想让串口中打印的字符串换行,并且对齐时,需要在字符串后面加上\r\n,注意\r和\n缺一不可,它不像我们写C语言程序时只用转义字符'\n'代表换行,这里是回车加换行的意思。

1、发送中断请求标志位TI:(习题1中使用了TI)

  • 使用原因:在习题1中,我们通过不断往SBUF寄存器写入1个字符的方法来输出字符串,但是发现在给SBUF连续写入字符时没有延时的话PC端不能显示一整个字符串,只能显示一个字符。回忆我们上一节刚刚讲过串行移位寄存器。串口在输出数据时,先往8位的输出数据缓冲寄存器SBUF中写入数据(1个字符),然后再放到串行输出移位寄存器中,由它将二进制数顺序发送给PC。我们需要注意的是,我们在用单片机给PC发送数据时,单片机先把数据扔到SBUF中,然后经过移位,串口数据移位的过程是需要时间的,所以我们不能以非常快的速度把数据一股脑扔到SBUF中。那么每往SUBF写入一个字符后,隔多少时间进行下一次写入比较合适呢(延时有点多的话,比如说10ms,那么PC上打印的字符串会出现刷屏的现象)?答:查阅手册,我们发现有比延时更好用的东西,就是SCON寄存器的发送中断请求标志位TI,可以控制串口数据的移位时间
  • 原理:目前不使用串口的中断,而是利用了串口中断触发的特点(硬件底层的电气特性),也就是串行发送数据的第8位结束后硬件会自动将TI“置1”。回忆超声波测距传感器demo,我们可以用空循环体等待串行发送数据第8位结束的方法来间接表示一位数据的发送时间,最后软件复位TI。这样就不需要知道你串行发送完一个字节数据需要多少时间,就可以解决PC上打印的字符串刷屏的现象。

  

习题1(向PC发送字符串):【项目工程文件夹

  1. 思路:
    全局变量:
    1.sfr指令直接找到AUXR寄存器: sfr AUXR = 0X8E;    //因为AUXR没有在reg52.h中声明
    1. 调用API2. 初始化串口: UartInit();
    2. while死循环,每隔一秒通过串口给PC发送一个字符串
        2.1 调用API1,软件延时1s: Delay1000ms();
        2.2 调用API4,给输出数据缓冲寄存器SBUF发送一条字符串: sendString("hello shuaige\r\n");
    /* 一级函数:f1、f2、f4 */
    f1. 封装软件延时1s的API,用于每隔一秒给串口缓冲寄存器发送字符串: void Delay1000ms();
    f2. 封装初始化串口的API: void UartInit(void);
        f2.1 禁用ALE信号: AUXR = 0X01;
        f2.2 让串口以方式1工作(8位UART,可变波特率),并允许串口接收: SCON = 0x50;
        f2.3 让定时器1以8位重载工作模式工作:
            TMOD &= 0xDF;
            TMOD |= 0x20;
        f2.4 根据波特率为9600,波特率不翻倍,设置定时器1的初值:
            TH1 = 0xFD;
            TL1 = 0xFD;
        f2.5 定时器开始数数: TR1 = 1;
    f4. 封装给PC发送字符串的API: void sendString(char *str); //形参是字符串的地址
        f4.1 定义一个字符指针变量p用来保存字符串首地址: char *p = str;
        f4.2 while循环,控制循环的变量是*p,当*p != '\0' 时,进入循环,进行单个字符的发送
            f4.2.1 通过指针间接访问字符串字符,再调用API3. 发送单个字符: sendByte(*p);
            f4.2.2 修改循环变量p的值,让指针p偏移: p++;
    /* 二级函数:f3 */
    f3. 封装定时给PC发送一个字符的API: void sendByte(char data_msg);  //形参是字符值
        f3.1 往SBUF寄存器中写入字符data_msg: SBUF = data_msg;
        f3.2 根据串口发送中断触发位TI,利用空循环体暂停程序: while(TI == 0);
        f3.3 程序复位TI: TI = 0;

  2. 代码:
    #include "reg52.h"
    #include "intrins.h"
    
    sfr AUXR = 0x8E;
    
    /* API1. 软件延时1s,用于每隔一秒给串口缓冲寄存器发送字符串 */
    void Delay1000ms();
    /* API2. 初始化串口 */
    void UartInit(void);
    /* API3. 软件延时10ms,用于给串行移位寄存器移动数据预留时间(弃用) */
    void Delay10ms();
    /* API3. 通过串口定时给PC发送一个字符 */
    void sendByte(char data_msg);
    /* API4. 通过串口给PC发送一个字符串 */
    void sendString(char *str);
    
    void main(void)
    {
        UartInit();
    	while(1){
    		Delay1000ms();
    		sendString("hello shuaige\r\n");
    	}
    }
    
    void Delay1000ms()		//@11.0592MHz
    {
    	unsigned char i, j, k;
    
    	_nop_();
    	i = 8;
    	j = 1;
    	k = 243;
    	do
    	{
    		do
    		{
    			while (--k);
    		} while (--j);
    	} while (--i);
    }
    
    void UartInit(void)		//9600bps@11.0592MHz
    {
    	AUXR = 0x01;
    	SCON = 0x50;	//8位UART,允许串口接收
    	TMOD &= 0xDF;
    	TMOD |= 0x20;	//定时器8位重载工作模式
    	TH1 = 0xFD;
    	TL1 = 0xFD;		//9600波特率初值
    	TR1 = 1;
    }
    
    void Delay10ms()		//@11.0592MHz
    {
    	unsigned char i, j;
    
    	i = 18;
    	j = 235;
    	do
    	{
    		while (--j);
    	} while (--i);
    }
    
    void sendByte(char data_msg)
    {
    	SBUF = data_msg;
    	// Delay10ms();
    	while(TI == 0);
    	TI = 0;
    }
    
    void sendString(char *str)
    {
    	char *p = str;
    	while(*p != '\0'){
    		sendByte(*p);
    		p++;
    	}
    }

2、接收中断请求标志位RI:

  • 使用原因:我们上一节刚刚讲过串行移位寄存器。串口在接收数据时,PC先将二进制数顺序发送给串行输入移位寄存器,再由它把数据顺序移动到输入数据缓冲寄存器SBUF中,最后串口从缓冲区接收到数据。同样的,数据经过移位是耗费时间的。所以我们想知道PC什么时候已经完成“通过串口将数据输入给单片机”这件事。而用“接收中断请求标志位RI”来帮助单片机判断是否接收到1字节数据。
  • 原理:目前不使用串口的中断,而是利用了串口中断触发的特点(硬件底层的电气特性),也就是串行接收数据的第8位结束后硬件会自动将RI“置1”。所以我们可以用查询法来判断一个字符是否已经通过串行移位寄存器移动到SBUF寄存器,最后软件复位RI

 

习题2(PC发送字符指令给单片机):PC通过串口点亮单片机LED灯【项目工程文件夹

  • tip1【SCON寄存器的REN“置1”后单片机才能接收数据】:我们在串口初始化函数中已经设置好了

 

  1. 思路:在习题1的基础上修改代码
    全局变量 | 增加
    1. sbit指令找到P3这个I/O口组的第7位P3^7,也就是D5这个LED: sbit ledD5 = P3^7;
    main函数 | 修改
    1. 调用API2. 初始化串口: UartInit();
    2. 让D5先灭: ledD5 = 1;
    3. while死循环,每隔一秒通过串口给PC发送一个字符串,并且从PC接收一个字符数据
        3.1 调用API1,软件延时1s: Delay1000ms();
        3.2 调用API4,给输出数据缓冲寄存器SBUF发送一条字符串: sendString("hello shuaige\r\n");
    	3.3 用“接收中断请求标志位RI”来帮助单片机判断是否接收到1字节数据,判据是RI == 1
            3.3.1 如果是,说明已经接收到1位数据
            	从输入数据缓冲寄存器SBUF中接收数据,保存在变量cmd中: cmd = SBUF;
    			如果cmd是'o',则点亮D5,如果cmd是'C',则关闭D5;
    	3.4 在接受到1字节数据后,程序复位RI: RI = 0;

  2. 代码:
    #include "reg52.h"
    #include "intrins.h"
    
    sfr AUXR = 0x8E;
    sbit ledD5 = P3^7;
    
    /* API1. 软件延时1s,用于每隔一秒给串口缓冲寄存器发送字符串 */
    void Delay1000ms();
    /* API2. 初始化串口 */
    void UartInit(void);
    /* API3. 通过串口给PC发送一个字符 */
    void sendByte(char data_msg);
    /* API4. 通过串口给PC发送一个字符串 */
    void sendString(char *str);
    
    void main(void)
    {
    	char cmd;
        UartInit();
    	ledD5 = 1;
    	while(1){
    		Delay1000ms();
    		sendString("hello shuaige\r\n");
    		if(RI == 1){
    			cmd =  SBUF;
    			if(cmd == 'o'){
    				ledD5 = 0;
    			}else if(cmd == 'c'){
    				ledD5 = 1;
    			}
    		}
    		RI = 0;
    	}
    }
    
    void Delay1000ms()		//@11.0592MHz
    {
    	unsigned char i, j, k;
    
    	_nop_();
    	i = 8;
    	j = 1;
    	k = 243;
    	do
    	{
    		do
    		{
    			while (--k);
    		} while (--j);
    	} while (--i);
    }
    
    void UartInit(void)		//9600bps@11.0592MHz
    {
    	AUXR = 0x01;
    	SCON = 0x50;	//8位UART,允许串口接收
    	TMOD &= 0xDF;
    	TMOD |= 0x20;	//定时器8位重载工作模式
    	TH1 = 0xFD;
    	TL1 = 0xFD;		//9600波特率初值
    	TR1 = 1;
    }
    
    void sendByte(char data_msg)
    {
    	SBUF = data_msg;
    	// Delay10ms();
    	while(TI == 0);
    	TI = 0;
    }
    
    void sendString(char *str)
    {
    	char *p = str;
    	while(*p != '\0'){
    		sendByte(*p);
    		p++;
    	}
    }

2.串口中断

1、为什么需要串口中断?:

  1. 在习题2中,经过测试可以发现电脑通过串口点亮单片机的LED有点延迟,这是因为我们让串口处于全双工通信状态下时,每隔一秒无脑给PC发送数据的同时又要对从PC那里接收到的数据进行判断,这导致PC的数据即使已经被保存在输入数据缓冲寄存器SBUF中了,但是单片机因为还在数数(软件延时)没有马上去取这个数据。
  2. 类比于感应开关盖垃圾桶项目中利用外部中断记住振动传感器的信号,我们需要在单片机串口接收到PC的数据后,立马挂起串口发送的程序,先去响应接收中断,再进行串口发送。
  3. 你可能在有点工作经验的人口中听到“心跳包”这个词,或者hearbeat,意思就是让单片机每隔1秒给PC(或者服务器、上位机)发送一个字符或者一个字符串的心跳包,代表单片机“没死”。然后让我们的具体业务放在另一个“线程”当中。

2、串口中断配置:

  1. 串口中断触发方式:SCON寄存器的TI 和 RI,分别是串口发送中断请求标志(transfer interrupt) 和 串口接收中断请求标志(receive interrupt)。另外我们可以发现串口中断程序没有细分为发送中断还是接收中断,因此需要人为的在中断处理程序根据用串口中断触发方式进行判断。
  2. 串口中断号: 4 ,查阅51芯片手册第6.1小节的表6-1。
  3. 串口中断开关:先在51芯片手册中找到中断系统结构图示意图(6.1小节),发现串口对应的中断开关有ES和EA,再在手册中查找ES(enable serial),我们发现它是IE寄存器的第4位,是串行口1中断允许位

 

 

 

习题3(PC串口中断发送字符给单片机):【项目工程文件夹

  1. 思路:在习题2的基础上修改
    全局变量 | 增加
    1. 定义一个用于接收PC通过串口发送来的字符的全局变量cmd: char cmd;  
    //cmd的传递路线为:SBUF ——> 串口中断(中断4)
    main函数 | 修改
    1. 调用API2. 初始化串口: UartInit();
    2. 让D5先灭: ledD5 = 1;
    3. while死循环,每隔一秒通过串口给PC发送一个字符串
        3.1 调用API1,软件延时1s: Delay1000ms();
        3.2 调用API4,给输出数据缓冲寄存器SBUF发送一条字符串: sendString("hello shuaige\r\n");
    中断: 
    中断4: 封装串口中断的中断服务程序, void Uart_Routine()   interrupt 4
    	4.1 中断处理程序中,对于接收中断的响应,判据是RI == 1
        	4.1.1 在接受到1字节数据后,程序复位RI: RI = 0;
    		4.1.2 从输入数据缓冲寄存器SBUF中接收数据,保存在变量cmd中: cmd = SBUF;
    		4.1.3 对指令cmd进行判断: 如果cmd是'o',则点亮D5,如果cmd是'C',则关闭D5;
        4.2 中断处理程序中,对于发送中断的响应,判据是TI == 1
        	暂时不做任何事情
    /* 一级函数:f1、f2、f4 */ | 修改f2
    f2. 封装初始化串口的API: void UartInit(void); | 增加开启串口中断的语句
        f2.1 禁用ALE信号: AUXR = 0X01;
        f2.2 让串口以方式1工作(8位UART,可变波特率),并允许串口接收: SCON = 0x50;
        f2.3 让定时器1以8位重载工作模式工作:
            TMOD &= 0xDF;
            TMOD |= 0x20;
        f2.4 根据波特率为9600,波特率不翻倍,设置定时器1的初值:
            TH1 = 0xFD;
            TL1 = 0xFD;
        f2.5 定时器开始数数: TR1 = 1;
    	f2.6 开启串口中断:
    		EA = 1;
    		ES = 1;

  2. 代码:
    #include "reg52.h"
    #include "intrins.h"
    
    sfr AUXR = 0x8E;
    sbit ledD5 = P3^7;
    char cmd;
    
    /* API1. 软件延时1s,用于每隔一秒给串口缓冲寄存器发送字符串 */
    void Delay1000ms();
    /* API2. 初始化串口 */
    void UartInit(void);
    /* API3. 通过串口给PC发送一个字符 */
    void sendByte(char data_msg);
    /* API4. 通过串口给PC发送一个字符串 */
    void sendString(char *str);
    
    void main(void)
    {
        UartInit();
    	ledD5 = 1;
    	while(1){
    		Delay1000ms();
    		sendString("hello shuaige\r\n");
    	}
    }
    
    void Uart_Routine()    interrupt 4
    {
    	/* 中断处理程序中,对于接收中断的响应 */
    	if(RI == 1){	
    		RI = 0;
    		cmd = SBUF;
    		if(cmd == 'o'){
    			ledD5 = 0;
    		}else if(cmd == 'c'){
    			ledD5 = 1;
    		}
    	}
    	/* 中断处理程序中,对于发送中断的响应 */
    	if(TI == 1){
    		// 暂时不做任何事情
    	}
    }
    
    void Delay1000ms()		//@11.0592MHz
    {
    	unsigned char i, j, k;
    
    	_nop_();
    	i = 8;
    	j = 1;
    	k = 243;
    	do
    	{
    		do
    		{
    			while (--k);
    		} while (--j);
    	} while (--i);
    }
    
    void UartInit(void)		//9600bps@11.0592MHz
    {
    	AUXR = 0x01;
    	SCON = 0x50;	//8位UART,允许串口接收
    	TMOD &= 0xDF;
    	TMOD |= 0x20;	//定时器8位重载工作模式
    	TH1 = 0xFD;
    	TL1 = 0xFD;		//9600波特率初值
    	TR1 = 1;
    	EA = 1;
    	ES = 1;			//开启串口中断
    }
    
    void sendByte(char data_msg)
    {
    	SBUF = data_msg;
    	// Delay10ms();
    	while(TI == 0);
    	TI = 0;
    }
    
    void sendString(char *str)
    {
    	char *p = str;
    	while(*p != '\0'){
    		sendByte(*p);
    		p++;
    	}
    }

3.串口支持单词型指令控制

1、可能遇到的复杂指令:今后可能会遇到几种数据格式,一些模块将这些指令通过串口传递给单片机

  1. open 或 close
  2. cmd-open 或 cmd-close
  3. c:1:open 或 c:0:close

2、一种串口指令处理方法:

  1. 程序中用字符数组存储串口接收到的字符串指令。
  2. 以第1种数据格式的指令为例,数据缓冲寄存器SBUF读取到的字符串存放在我们定义的字符数组中,但是顺序不一定从第0位开始存放。所以字符串指令“open”或“close”的位置是不确定的,因此不能用strcmp()函数来判断。
  3. 比如我们只关心字符串中有没有子串"op"或"en",或者有没有子串"cl"或"se"。所以我们使用strstr()函数

总结:这种处理方法对于上述指令够用了,但是处理复杂指令时可能会出错。想要完美的解决这一问题需要比较厉害的C语言功底,写出来的代码量也会比较大。

习题4(PC发送字符串指令给单片机):【项目工程文件夹

  1. 思路:在习题3的基础上修改
    宏定义 | 增加
    1. 定义符号常量len,用它代表用来接收串口数据的字符数组的长度: #define len 12 
    全局变量 | 增加
    1. 定义一个用于接收串口数据的字符数组cmd[]: char cmd[len];  
    //cmd[]的传递路线为:SBUF ——> 串口中断(中断4)
    中断 | 修改中断4
    中断4: 封装串口中断的中断服务程序, void Uart_Routine()   interrupt 4
        4.1 定义一个静态全局区的静态变量,用来表示数组cmd的下标: static int i = 0;
    	4.2 中断处理程序中,对于接收中断的响应,判据是RI == 1
        	4.2.1 在接受到1字节数据后,程序复位RI: RI = 0;
    		4.2.2 从输入数据缓冲寄存器SBUF中接收数据,保存在数组cmd的第i个元素中: cmd[i] = SBUF;
    		4.2.3 偏移数组下标: i++;
    		4.2.4 判断字符数组cmd是否存满了,判据是 i == len
            	4.2.4.1 如果是,那么需要从头开始存放: i = 0;
                4.2.4.2 否则,那么什么也不做,继续往下执行
            //内在逻辑:由于cmd长度的限制,当字符串指令超过len时,我们需要覆盖掉原先的字符
            4.2.5 判断当前字符串cmd中是否含有子串"en",判据是strstr(cmd,"en")!=NULL
            	4.2.5.1 如果是,说明我们大概率读到了open,代表点亮LED
                	点亮D5这个LED: ledD5 = 0;
    				既然已经完成命令,我们希望SBUF中的数据能够从头开始存放新的指令: i = 0;
    				清空cmd字符串的内容: memset(cmd, '\0', len);
    			4.2.5.2 否则,如果字符串cmd中含有子串"se",说明我们大概率读到了close
                	熄灭D5这个LED: ledD5 = 1;
    				既然已经完成命令,我们希望SBUF中的数据能够从头开始存放新的指令: i = 0;
    				清空cmd字符串的内容: memset(cmd, '\0', len);
        4.3 中断处理程序中,对于发送中断的响应,判据是TI == 1
        	暂时不做任何事情

  2. 代码:
    #include "reg52.h"
    #include "intrins.h"
    #include <string.h>
    
    #define len 12
    sfr AUXR = 0x8E;
    sbit ledD5 = P3^7;
    char cmd[len];
    
    /* API1. 软件延时1s,用于每隔一秒给串口缓冲寄存器发送字符串 */
    void Delay1000ms();
    /* API2. 初始化串口 */
    void UartInit(void);
    /* API3. 通过串口给PC发送一个字符 */
    void sendByte(char data_msg);
    /* API4. 通过串口给PC发送一个字符串 */
    void sendString(char *str);
    
    void main(void)
    {
        UartInit();
    	ledD5 = 1;
    	while(1){
    		Delay1000ms();
    		sendString("hello shuaige\r\n");
    	}
    }
    
    void Uart_Routine()    interrupt 4
    {
    	static int i = 0;	//静态全局区的变量
    	/* 中断处理程序中,对于接收中断的响应 */
    	if(RI == 1){	
    		RI = 0;
    		cmd[i] = SBUF;
    		i++;
    		if(i == len){
    			i = 0;
    		}
    		if(strstr(cmd,"en")!=NULL){
    			ledD5 = 0;
    			i = 0;
    			memset(cmd,'\0',len);
    		}else if(strstr(cmd,"se")!=NULL){
    			ledD5 = 1;
    			i = 0;
    			memset(cmd,'\0',len);
    		}
    	}
    	/* 中断处理程序中,对于发送中断的响应 */
    	if(TI == 1){
    		// 暂时不做任何事情
    	}
    }
    
    void Delay1000ms()		//@11.0592MHz
    {
    	unsigned char i, j, k;
    
    	_nop_();
    	i = 8;
    	j = 1;
    	k = 243;
    	do
    	{
    		do
    		{
    			while (--k);
    		} while (--j);
    	} while (--i);
    }
    
    void UartInit(void)		//9600bps@11.0592MHz
    {
    	AUXR = 0x01;
    	SCON = 0x50;	//8位UART,允许串口接收
    	TMOD &= 0xDF;
    	TMOD |= 0x20;	//定时器8位重载工作模式
    	TH1 = 0xFD;
    	TL1 = 0xFD;		//9600波特率初值
    	TR1 = 1;
    	EA = 1;
    	ES = 1;			//开启串口中断
    }
    
    void sendByte(char data_msg)
    {
    	SBUF = data_msg;
    	// Delay10ms();
    	while(TI == 0);
    	TI = 0;
    }
    
    void sendString(char *str)
    {
    	char *p = str;
    	while(*p != '\0'){
    		sendByte(*p);
    		p++;
    	}
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/519200.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

利用notepad++处理数据,再用excel做则线图

1、利用串口调试XCOM V2.8得到数据 2、利用Notepad编辑数据 利用正则表达式 删除时间戳 移除空行 继续删掉不要的数据 3、用excel生成折线图 复制数据到excel excel自动根据上文公式填充计算 输入0.1和0.2 框选0.1和0.2&#xff0c;下拉

JavaScript-jQuery的使用 + JS的案例

目录 点击更换图片 猜数字 搜索页面展示 表白墙 点击更换图片 我们先看下面这个例子: 使用input里面的button按钮, 并且利用函数, 将一个搜狗logo转换为百度logo: <!DOCTYPE html> <html lang"en"> <head><meta charset&…

Maven下载安装及IDEA配置Maven的超详细教程

Maven下载安装及IDEA配置Maven的超详细教程 1、IntelliJ IDEA 下载、安装及配置过程2、maven下载、安装、配置过程2.1 mavan下载2.2 安装2.3 配置 3、在IDEA中配置Maven3.1 进入设置界面3.2 maven配置 4、IDEAmaven创建工程示例 Maven是一个能使我们的java程序开发节省时间和精…

ssl证书过期

SSL证书验证网站所有者的身份&#xff0c;并为其访问者建立与服务器的安全加密连接。它保护他们的安全和隐私。 但SSL证书并非永远有效。与您的驾驶执照或护照一样&#xff0c;SSL证书也有过期日期。过期日期后&#xff0c;服务器的身份不再受信任。 为什么网站安全证书会过期…

C++ 类与对象中类的深入知识点+完整思维导图+基本练习题+深入细节+通俗易懂建议收藏

绪论 本章我们接着对类和对象进行探索&#xff0c;这是一个在我们c中比较重要的知识点&#xff0c;下面我们才是我们类和对象的更加深入且困难的知识点&#xff0c;希望你能通过这篇文章对类其有更加深入的了解。 话不多说安全带系好&#xff0c;发车啦&#xff08;建议电脑观看…

使用Taskflow完成简历信息提取

构建模型的步骤&#xff1a; 首先要进行数据处理&#xff0c;抽取简历文件中的数据。 首先要准备数据集&#xff0c;大赛提供的数据集中多为word文档&#xff0c;都为.docx格式&#xff0c; docx文件是基于 XML 的&#xff0c;可以包含文本&#xff0c;对象&#xff0c;样式&…

想让你的应用程序更加可靠?来了解Spring事务的回滚机制吧!

嗨&#xff0c;大家好&#xff0c;我是小米&#xff0c;今天要和大家聊一聊关于Spring框架事务的回滚源码实现。 相信对于使用Spring框架的小伙伴来说&#xff0c;事务管理肯定是非常重要的一个环节&#xff0c;事务的管理不好很容易出现各种问题&#xff0c;如数据不一致等。…

二十五:修改交易

1.功能需求 点击交易的复选框&#xff0c;然后点击修改按钮。进行数据的页面填充 1.流程图 1.代码实现 TranMapper /*** 根据id查询交易*/Tran selectTranDetailFortranId(String tranId); <!-- Tran selectTranDetailFortranId(String tranId);--><select id"…

项目集战略一致性

项目集战略一致性是识别项目集输出和成果&#xff0c;以便与组织的目标和目的保持一致的绩效领域。 本章内容包括&#xff1a; 1 项目集商业论证 2 项目集章程 3 项目集路线图 4 环境评估 5 项目集风险管理战略 项目集应与组织战略保持一致&#xff0c;并促进组织效益的实现。为…

【博客系统】页面设计(附完整源码)

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 一、页面介绍 二、预期效果 1、博客列表页效…

刚面试了一位5年的Android开发,一问三不知,他还反怼我...

最近帮部门主管面试了很多人&#xff0c;从简历上看这些人的工作年限都不短&#xff0c;但做的都是一些传统的项目&#xff0c;想做现在大环境越来越难&#xff0c;大家找工作都不容易&#xff0c;就打算见一见。 在沟通中发现&#xff0c;由于年限不小&#xff0c;他们的定位…

十、Feign客户端

目录 1、在springcloud-order项目中引入Feign客户端的依赖 2、在server-order服务的启动类中添加注解EnableFeignClients 3、使用FeignClient注解声明Feign客户端需要调用的远程接口 3.1、server-pay服务提供远程接口Controller 3.2、server-member服务提供远程接口Contro…

ES基础知识总结含SQL、DSL、GOLANG

一、简介 Elasticsearch是一个基于Lucene的全文搜索和分析引擎&#xff0c;Lucene Core是一个完全用Java编写的高性能、全功能搜索引擎库。 它可以快速地存储、实时搜索和分析大量数据。 它可以扩展到上百台服务器&#xff0c;处理PB级数据。PB 2^50 Byte&#xff0c; 在数…

联通数科面试准备

Spring中Bean的生命周期 Spring Bean的生命周期全过程分为5个阶段&#xff0c;创建前准备阶段、创建实例阶段、依赖注入阶段和容器缓存阶段以及销毁实例阶段。 阶段1&#xff1a;创建前准备阶段这个阶段主要是在开始Bean加载之前&#xff0c;从Spring上下文中去获取相关的配置…

如何使用Alchemy开发NFT智能合约(ERC721)

&#x1f978; 本教程翻译自官网&#xff1a;[https://docs.alchemy.com/docs](https://docs.alchemy.com/docs)。对部分内容进行了修改。教程中所有实例经过本人实践&#xff0c;代码可见&#xff1a;https://github.com/ChuXiaoYi/web3Study 使用Solidity开发智能合约并在区块…

2022 第十三届蓝桥杯大赛软件赛决赛, 国赛,C/C++ 大学B组题解

2022 第十三届蓝桥杯大赛软件赛决赛, 国赛&#xff0c;C/C 大学B组题解 文章目录 第1题 —— 2022 &#xff08;5分&#xff09;第2题 —— 钟表 &#xff08;5分&#xff09;第3题 —— 卡牌 &#xff08;10分&#xff09;第4题 —— 最大数字 &#xff08;10分&#xff09;第…

bbys_tu_2016

1,三连 思路&#xff1a;栈溢出 2&#xff0c;IDA分析 利用函数&#xff1a; 思路:ret2text 偏移&#xff1a;24 3&#xff0c;payload from pwn import * context.log_level"debug"rremote(node4.buuoj.cn,29195)flag 0x804856Dpayload 24 * a p32(flag) r.se…

Unittest单元测试框架之unittest构建测试套件

构建测试套件 在实际项目中&#xff0c;随着项目进度的开展&#xff0c;测试类会越来越多&#xff0c;可是直到现在我 们还只会一个一个的单独运行测试类&#xff0c;这在实际项目实践中肯定是不可行的&#xff0c;在 unittest中可以通过测试套件来解决该问题。 测试套件&…

七、Zookeeper注册中心

目录 1、下载Zookeeper的服务jar包 2、下载好jar包后解压放到合适的目录&#xff08;目录最好不要有中文及空格&#xff09; 3、进入解压后的conf目录&#xff0c;复制zoo_sample.cfg文件并重命名为zoo.cfg&#xff0c;修改zoo.cfg文件内容如下 4、运行bin目录下的zkServer…

split,paste,eval命令及正则表达式

一、split命令 将 linux 下的一个大文件拆分成若干小文件 1.语法格式 格式&#xff1a;split 选项 参数 原始文件 拆分后文件名前缀 常用选项: -l&#xff1a;以行数拆分 -b&#xff1a;以大小拆分 2.命令演示 2.1选项 -l &#xff1a;以行数分隔 cat -n anaconda-ks.cfg…