ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

智能教室控制系统

2021-06-28 11:06:40  阅读:167  来源: 互联网

标签:TIM void 教室 控制系统 智能 RC522 uint8 GPIO define


智能教室控制系统

引言

概述

该系统通过上位机C#控制下位机STM32,实现教室打卡考勤功能,通过打卡对数据库SQLserver进行增删改查,同时能将数据库的数据导出表格,下位机用到RFID的RC522模块,舵机、风扇,ws2812灯环。风扇通过调温度阈值,自动开关。上位机和下位机通过串口进行通信。

运用技术:C#桌面级winform程序、SQL server、stm32f103zet6单片机

技术路线:软件部分:C#:三方API接入 json解析、串口通信、调用数据库

硬件部分:Rfid射频刷卡,舵机,风扇

舵机模块
在这里插入图片描述橙色线接脉冲线,红色线接+5V,黑色接GND;

RC522模块
在这里插入图片描述
上位机共有5个界面,分别是注册,登录,忘记密码,主界面,导出表单。
在这里插入图片描述

登录界面

在这里插入图片描述

忘记密码界面

在这里插入图片描述

注册界面

在这里插入图片描述

导出表单

代码部分

下位机代码

主函数

#include "bsp.h"				/* 底层硬件驱动 */

#include "pwm.h"

/*
STM32 每个系列都会有唯一的一个芯片序列号(96 位 bit):
STM32F10X 的地址是 0x1FFFF7E8 
STM32F20X 的地址是 0x1FFF7A10
STM32F30X 的地址是 0x1FFFF7AC
STM32F40X 的地址是 0x1FFF7A10
STM32L1XX 的地址是 0x1FF80050
*/

/* SN 起始地址 */
#define STM32F10X_SN_ADDR 0x1FFFF7E8


/* 定义例程名和例程发布日期 */
#define EXAMPLE_NAME "WSNEP_V01-051_SPI 实验( RC522) "
#define EXAMPLE_DATE "2021-06-01"
#define DEMO_VER "1.0"


/* 定义 LCD 显示相关公共信息 */
#define DEV_NAME "Wisdomclassroom"
#define LCD_EXAMPLE_NAME "RFID"


const unsigned char str1[] = {0x08,0x00,0x29,0x00,0xCA,0x00,0x4C,0xFF,0x78,0x92,0x4C,0x92,0x4A,0x92,0x08,0x92,0x00,0x92,0x7E,0x92,0x42,0x92,0x42,0xFF,0x42,0x00,0x7E,0x00,0x00,0x00,0x00,0x00};/*"智",0*/
const unsigned char str2[] = {0x44,0x01,0x54,0x06,0x55,0x10,0xFF,0x50,0x55,0x56,0x55,0x51,0x45,0x51,0x01,0x59,0x45,0x55,0x55,0x51,0x55,0x51,0xFF,0x53,0x55,0xF0,0x54,0x04,0x44,0x03,0x00,0x00};/*"慧",1*/
const unsigned char str3[] = {0x04,0x20,0x25,0x50,0x25,0x92,0x25,0x11,0xFF,0x7E,0x25,0xA0,0x2D,0x20,0x14,0x21,0x21,0x02,0x0E,0x04,0xF1,0xC8,0x10,0x30,0x10,0xCC,0x1F,0x02,0x10,0x01,0x00,0x00};/*"教",2*/
const unsigned char str4[] = {0x08,0x02,0x30,0x02,0x24,0x12,0x24,0x92,0x25,0x92,0x26,0x92,0xA4,0x92,0x64,0xFE,0x24,0x92,0x24,0x92,0x25,0x92,0x24,0xD2,0x24,0x12,0x28,0x02,0x30,0x02,0x00,0x00};/*"室",3*/
const unsigned char str5[] = {0x02,0x00,0x42,0x00,0x33,0xFE,0x00,0x04,0x00,0x08,0x22,0x00,0x2A,0xFF,0x2A,0xA8,0x2A,0xA8,0xFE,0xA8,0x2A,0xAA,0x2A,0xA9,0x2A,0xFE,0x22,0x00,0x02,0x00,0x00,0x00};/*"请",4*/
const unsigned char str6[] = {0x00,0x08,0x00,0x70,0x7F,0x80,0x48,0xFC,0x48,0x80,0x48,0x80,0x4F,0xFF,0x48,0x88,0x48,0x84,0x78,0xF8,0x00,0x00,0x0F,0xF0,0x00,0x02,0x00,0x01,0xFF,0xFE,0x00,0x00};/*"刷",5*/
const unsigned char str7[] = {0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0x02,0x00,0xFF,0xFF,0x22,0x00,0x22,0x00,0x22,0x40,0x22,0x20,0x22,0x10,0x22,0x08,0x02,0x00,0x02,0x00,0x00,0x00};/*"卡",6*/



void IC_test( void )
{
	char cStr [ 30 ];
	char EptStr[30];
	uint8_t ucArray_ID [ 4 ]; /*先后存放 IC 卡的类型和 UID(IC 卡序列号)*/
	uint8_t ucStatusReturn; /*返回状态 */
	static u16 ucLineCount = 170; /* LCD 起始行为 170 */
	
	sprintf ( EptStr, "                "); /* LCD 显示空白,为清空 LCD 显示做准备 */
	/*寻卡*/
	if ( ( ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID ) ) != MI_OK )
	{
		/*若失败再次寻卡*/
		ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID );
	}
	
	if ( ucStatusReturn == MI_OK )
	{
	//		printf("----------------------------\r\n");
	//		printf("0x%02X%02X\r\n",ucArray_ID [ 0 ],ucArray_ID [ 1 ]);
			/*防冲撞(当有多张卡进入读写器操作范围时,防冲突机制会从其中选择一张进行操作) */
		if ( PcdAnticoll ( ucArray_ID ) == MI_OK )
		{
			sprintf ( cStr, "%02X%02X%02X%02X",ucArray_ID [ 0 ],ucArray_ID [ 1 ],ucArray_ID [ 2 ],ucArray_ID [ 3 ]);
			
			//printf("%s",ucArray_ID);		
			
//			USART1_Send_Data((uint8_t*)ucArray_ID,4);
			
			printf ( "%s",cStr );
			
			if ( ucLineCount == 290 ) /* 最多同时显示 6 行 */
			{
				for(ucLineCount=170;ucLineCount<=290;ucLineCount+=20)
				{
					LCD_ShowString(30,ucLineCount,200,16,16,(u8*)EptStr); //循环清空 6 行 LCD 显示
				}
				ucLineCount=170; /* 设置 LCD 起始行为 170 */
			}			
			LCD_ShowString(30,ucLineCount,200,16,16,(u8*)cStr); //显示读取到的卡号
			ucLineCount += 20; /* 设置下一次 LCD 显示行,自增 20 */
		}
	}
}


/*
*********************************************************************************************************
*	函 数 名: main
*	功能说明: c程序入口
*	形    参:无
*	返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{		
	uint8_t lcd_id[12]; /* 存放 LCD ID 字符串 */
//	uint8_t a0;
		
	/*
	ST 固件库中的启动文件已经执行了 SystemInit() 函数,该函数在 system_stm32f10x.c 文件,主要功能是
	配置 CPU 系统的时钟,内部 Flash 访问时序,配置 FSMC 用于外部 SRAM
	*/
	bsp_Init(); /* 硬件初始化 */
	TIM_Init();
//	SMBus_Init();//人体红外初始化
//	bsp_InitUART5(9600);/*注意,串口 4 初始化放在 LCD 之前*/
	TFTLCD_Init(); /* TFTLCD 初始化*/
	bsp_InitWS2812B(); /* 初始化 WS2812B */
	
	
	POINT_COLOR=BLUE;
	sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//将 LCD ID 打印到 lcd_id 数组。
	LCD_ShowString(30,40,200,24,24,(uint8_t*)DEV_NAME);
	LCD_ShowString(30,70,200,16,16,(uint8_t*)LCD_EXAMPLE_NAME);
	LCD_ShowString(30,90,200,16,16,(uint8_t*)DEMO_VER);
	LCD_ShowString(30,110,200,16,16,lcd_id); //显示 LCD ID
	LCD_ShowString(30,130,200,12,12,(uint8_t*)EXAMPLE_DATE);
	
	//汉字部分
	Show_Graph(30,150,(u8*)str1,16,0);
	Show_Graph(45,150,(u8*)str2,16,0);
	Show_Graph(60,150,(u8*)str3,16,0);
	Show_Graph(75,150,(u8*)str4,16,0);
	Show_Graph(105,150,(u8*)str5,16,0);
	Show_Graph(120,150,(u8*)str6,16,0);
	Show_Graph(135,150,(u8*)str7,16,0);
	
	bsp_InitRc522(); /* 初始化 RC522 的 SPI 端口 */
	PcdReset(); /* 复位 RC522 */
	
	M500PcdConfigISOType('A'); /* 设置工作方式 */
	
	bsp_StartAutoTimer(0, 300); /* 定时器 0 周期 300 毫秒 */
	bsp_StartAutoTimer(1, 500); /* 定时器 1 周期 500 毫秒 */
	while(1)
	{		
		bsp_Idle(); /* CPU 空闲时执行的函数,在 bsp.c */
		if (bsp_CheckTimer(0)) /* 定时到 */
		{
			bsp_LedToggle(2);		
		}
		if (bsp_CheckTimer(1)) /* 定时到 */
		{
			IC_test();
		}
	}
}

串口通信模块

#include "bsp.h"
#include "bsp_fan.h"
#include "bsp_uart5.h"

static const uint8_t temp[16] = {0XFD,0X00,0X0D,0X01,0X01,0XBB,0XD4,0XB8,0XE7,0XB4,0XF8,0XB4,0XF8,0XCE,0XD2,0XDC};
static const uint8_t temp1[16] = {0XFD,0X00,0X0D,0X01,0X01,0XC0,0XA4,0XB8,0XE7,0XB4,0XF8,0XB4,0XF8,0XCE,0XD2,0XD7};


#if EN_USART1_RX

uint8_t USART_RX_BUF[USART_REC_LEN];		//接收缓冲,最大USART_REC_LEN个字节,末字节为换行符
uint8_t ReceiveState=0;									//接收状态标记
uint16_t RxCounter=0;

u16 USART_RX_STA=0;       //接收状态标记

#endif 

/*
*********************************************************************************************************
*	函 数 名:bsp_InitUart
*	功能说明:初始化 CPU 的 USART1 串口硬件设备
*	形    参:无
*	返 回 值:无
*********************************************************************************************************
*/


/*
********************************************************************************************************
*/
//加入以下代码,支持 printf 函数,而不需要选择 use MicroLIB 
#if 1
#pragma import(__use_no_semihosting) 
/* 标准库需要的支持函数 */ 
struct __FILE 
{ 
int handle; 
}; 
FILE __stdout; 
/* 定义_sys_exit()以避免使用半主机模式 */ 

void _sys_exit(int x) 
{ 
x = x; 
} 
/*
*********************************************************************************************************
* 函 数 名: fputc
* 功能说明: 重定义 putc 函数,这样可以使用 printf 函数从串口 1 打印输出
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
int fputc(int ch, FILE *f)
{ 
while((USART1->SR&0X40)==0){};//;//循环发送,直到发送完毕 
 USART1->DR = (u8) ch; 
return ch;
}
#endif



void bsp_InitUart1(uint32_t baud)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	
#if EN_USART1_RX	//如果使能了接收
	
	NVIC_InitTypeDef NVIC_InitStructure;
	
#endif
	
	/* 串口 1 TX = PA9 RX = PA10 */
	/* 第 1 步: 配置 GPIO */
	/* 打开 GPIO 时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	/* 打开 UART 时钟 */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	/* 配置 USART Tx 为复用功能 */ //USART1_TX GPIOA.9
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_9;		//PA.9
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;	//复用推挽输出	
	GPIO_Init(GPIOA,&GPIO_InitStructure);		//初始化 GPIOA.9
	
	/* 配置 USART Rx 为复用功能 */ //USART1_RX GPIOA.10 初始化
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10;		//PA.10
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;	//浮空输入	
	GPIO_Init(GPIOA,&GPIO_InitStructure);		//初始化 GPIOA.10
	
	/* 第 2 步: 配置串口硬件参数 */
	USART_InitStructure.USART_BaudRate=baud;		//波特率
	USART_InitStructure.USART_WordLength=USART_WordLength_8b;		//字长为8位数据格式
	USART_InitStructure.USART_StopBits=USART_StopBits_1;		//一个停止位
	USART_InitStructure.USART_Parity=USART_Parity_No;		//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;	//无硬件数据流控制
	USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;		//收发模式
	
	USART_Init(USART1,&USART_InitStructure);	//初始化串口
	
#if EN_USART1_RX		//如果使能了接收

	/* 第 3 步: Usart1 NVIC 配置 */
	NVIC_InitStructure.NVIC_IRQChannel=USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;		//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority=3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;		//IRQ 通道使能
	NVIC_Init(&NVIC_InitStructure);		//根据指定的参数初始化 VIC 寄存器
	
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);		/* 开启串口接受中断 */
	USART_ITConfig(USART1,USART_IT_IDLE,ENABLE);		 /* 开启串口空闲中断 */
	
#endif	
	/* 第 4 步: 使能串口 1 */
	USART_Cmd(USART1,ENABLE);  //使能串口	
}

/*
*********************************************************************************************************
*	函 数 名:USART1_IRQHandler
*	功能说明:USART1 中断,主要是接收中断和空闲中断
*	形    参:无
*	返 回 值:无
*********************************************************************************************************
*/
void USART1_IRQHandler(void)		//串口 1 中断服务程序
{

	u8 Res;	
	bsp_InitUART5(9600);/*注意,串口 4 初始化放在 LCD 之前*/	
	while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
	Res=USART_ReceiveData(USART1);	//读取接收到的数据
	bsp_InitFan(); /* 初始化风扇 */
	if(Res=='1' || Res==0x01)		//接收到1或0x01,正转舵机3s,停止
	{
		TIM_SetCompare1(TIM1,10);
		delay_ms(3000);
		TIM_SetCompare1(TIM1,15);
	}
	
	if(Res=='2' || Res==0x02)		//接收到2或0x02,反转转舵机3s,停止
	{
		TIM_SetCompare1(TIM1,20);
		delay_ms(3000);
		TIM_SetCompare1(TIM1,15);
	}
	
	if(Res=='3'||Res==0x03) 		//开灯环
	{
		WS2812_effect(1);
	}
	
	if(Res=='4'||Res==0x04)			//关灯环
	{
		WS2812_effect(0);
	}
	
	if(Res=='5'||Res==0x05)
	{
		bsp_FanOn(1);
		bsp_FanOn(2);
	}
	
	if(Res=='6'||Res==0x06)
	{
		bsp_FanOff(1);
		bsp_FanOff(2);
	}	
	
	if(Res=='7'||Res==0x07)
	{
		bsp_BeepToggle();
		delay_ms(200);
		bsp_BeepToggle();

	}
	
	if(Res=='8'||Res==0x08)
	{
		bsp_BeepOff;
	}
			
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);		
		
		USART_RX_STA=0;		
	}	

	
	/*
*********************************************************************************************************
* 函 数 名: USART1_Send_Data
* 功能说明: USART1 发送 len 个字。
* 形 参: buf:发送区首地址
* len:发送的字节数 0~255
* 返 回 值: 无
*********************************************************************************************************
*/
void USART1_Send_Data(uint8_t *buf,uint8_t len)
{
	uint8_t t;
	for(t=0;t<len;t++) //循环发送数据
	{
		while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
		USART_SendData(USART1,buf[t]);
	}
	while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
}
		




uart.h


#ifndef _BSP_UART_H_
#define _BSP_UART_H_

#include "sys.h"

#define USART_REC_LEN				1024		//定义最大接收字节数1024
#define EN_USART1_RX				1				//使能(1)/禁止(0)串口1接收

extern uint8_t USART_RX_BUF[USART_REC_LEN];		//接收缓冲,最大USART_REC_LEN个字节,末字节为换行符
extern uint8_t ReceiveState;									//接收状态标记
extern uint16_t RxCounter;

void bsp_InitUart1(uint32_t baud);

#if EN_USART1_RX		//如果使能了接收

void Uart0_STA_Clr(void);

void USART1_Send_Data(uint8_t *buf,uint8_t len);

#endif



#endif

/***************************** 德致伦电子 DeZLinc (END OF FILE) *********************************/

PWM模块部分

#include "pwm.h"

/*
*********************************************************************************************************
* 函 数 名: bsp_GetRCCofGPIO
* 功能说明: 根据 GPIO 得到 RCC 寄存器
* 形 参:无
* 返 回 值: GPIO 外设时钟名
*********************************************************************************************************
*/


static void TIM_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
 
  // 输出比较通道 GPIO 初始化
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_8;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
 
 
	// BKIN引脚默认先输出低电平
	GPIO_ResetBits(GPIOB,GPIO_Pin_12);
}
 
static void Advance_TIM_Config(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 
	TIM_OCInitTypeDef  TIM_OCInitStructure;
	  // 开启定时器时钟,即内部时钟CK_INT=72M
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
 
/*--------------------时基结构体初始化-------------------------*/
	   //TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; 
	// 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
	TIM_TimeBaseStructure.TIM_Period= (200-1);	
	// 驱动CNT计数器的时钟 = Fck_int/(psc+1)
	TIM_TimeBaseStructure.TIM_Prescaler= (7200-1);	
	// 时钟分频因子 ,用于配置死区时间,没用到,随意
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;		
	// 计数器计数模式,设置为向上计数
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;		
	// 重复计数器的值,没用到,可以随意设置
	TIM_TimeBaseStructure.TIM_RepetitionCounter=0;	
	// 初始化定时器
	TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
 
	/*--------------------输出比较结构体初始化-------------------*/		
	
	// 配置为PWM模式2
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
	// 输出使能
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
	// 互补输出使能
	TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; 
	// 设置占空比大小
	TIM_OCInitStructure.TIM_Pulse = 0;
	// 输出通道电平极性配置
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
	
	// 输出通道空闲电平极性配置
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
	
	TIM_OC1Init(TIM1, &TIM_OCInitStructure);
	TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
	
	// 使能计数器
	TIM_Cmd(TIM1, ENABLE);	
	// 主输出使能,当使用的是通用定时器时,这句不需要
	TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
 
void TIM_Init(void)
{
	TIM_GPIO_Config();
	Advance_TIM_Config();
}

ws2812.c

#include "bsp.h"

static void send_Data_rgb(uint8_t r,uint8_t g, uint8_t b);

uint16_t LED_BYTE_Buffer[LED_BYTE_Buffer_Size]; //发送数组缓存

/*
*********************************************************************************************************
* 函 数 名: bsp_InitWS2812B
* 功能说明: 配置 WS2812 灯相关的 GPIO 和 TIM PWM 功能
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/

extern const uint8_t test_color[9][3] = {
	{0, 0, 0 },//黑色(不亮)
	{32, 32, 32},//白色
	{64, 0, 0 },//红色
	{0, 64, 0 },//绿色
	{0, 0, 64},//蓝色
	{64, 64, 0 },//黄色
	{64, 32, 0 },//橙色
	{64, 0, 64},//紫红色
	{0, 64, 64},//青色
};

void bsp_InitWS2812B(void)
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_APB2PeriphClockCmd(WS2812_GPIO_RCC, ENABLE); //使能 GPIO 时钟
	
	GPIO_InitStructure.GPIO_Pin = WS2812_GPIO_Pin;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(WS2812_GPIO_Port, &GPIO_InitStructure);
	
	RCC_APB1PeriphClockCmd(WS2812_TIM_RCC, ENABLE); //使能定时器 x 时钟
	
	/* Time base configuration */
	TIM_TimeBaseStructure.TIM_Period = 89; // 800kHz = 72M/(89+1)/(0+1)=800KHz
	TIM_TimeBaseStructure.TIM_Prescaler = 0;
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数模式
	TIM_TimeBaseInit(WS2812_TIM, &TIM_TimeBaseStructure); //根据 TIM_TimeBaseInitStruct 中指定的参数初始化TIMx 的时间基数单位
	
	/* PWM1 Mode configuration: Channelx */
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM 脉冲宽度调制模式 1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
	TIM_OCInitStructure.TIM_Pulse = 0;
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM 输出比较极性高
	
	WS2812_TIM_OCxInit(WS2812_TIM, &TIM_OCInitStructure); //配置输出设置函数
	/* 配置 DMA */
	
	/* 使能 DMA 时钟 */
	RCC_AHBPeriphClockCmd(WS2812_DMA_RCC, ENABLE);
	/* 配置 WS2812 所用 TIM 的 DMA 通道信息 */
	DMA_DeInit(WS2812_DMA_CH);
	
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&WS2812_DMA_ADDR; //DMA 外设基地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)LED_BYTE_Buffer; //DMA 内存基地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; //数据传输方向,从内存读取发送到外设
	DMA_InitStructure.DMA_BufferSize = LED_BYTE_Buffer_Size; //DMA 通道的 DMA 缓存的大小
	
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为 16 位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为 16 位
	
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//工作在正常模式 // stop DMA feed after buffer size is reached
	DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA 通道 x 拥有高优先级
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA 通道 x 没有设置为内存到内存传输
	
	DMA_Init(WS2812_DMA_CH, &DMA_InitStructure); //根据 DMA_InitStruct 中指定的参数初始化 DMA 的通道
	/* 只能使用通道 x TIMx_UP */
	TIM_DMACmd(WS2812_TIM, TIM_DMA_Update, ENABLE);
}
/*
*********************************************************************************************************
* 函 数 名: send_Data_rgb
* 功能说明: 发送一次数据
* 形 参: red 红色数值, green 绿色数值, blue 蓝色数值
* 返 回 值: 无
*********************************************************************************************************
*/
static void send_Data_rgb(uint8_t red,uint8_t green, uint8_t blue)
{
	
	uint8_t i=0;
	//注意需要发送的数据顺序高位->低位的顺序 是 绿->红->蓝
	uint32_t rgb_value = ( ( (uint32_t)green ) << 16 ) | ( ( (uint32_t)red ) << 8 ) | ( (uint32_t)blue );
	
	for(i=0;i<24;i++)
	{
		//判断最高位是否为 1,而赋值
		LED_BYTE_Buffer[i] = ( ( rgb_value << i ) & 0x800000 ) > 0 ? TIMING_ONE : TIMING_ZERO;
	}
	
	DMA_SetCurrDataCounter(WS2812_DMA_CH, LED_BYTE_Buffer_Size); // 装载需要发送的数据长度到 DMA 通道
	
	DMA_Cmd(WS2812_DMA_CH, ENABLE); // 使能对应的 DMA 通道
	
	TIM_Cmd(WS2812_TIM, ENABLE); // 使能对应的 TIMx
	
	while(!DMA_GetFlagStatus(WS2812_DMA_TC)); // 等待传输完毕
	
	TIM_Cmd(WS2812_TIM, DISABLE); // 失能对应的 TIMx
	DMA_Cmd(WS2812_DMA_CH, DISABLE); // 失能对应的 DMA 通道
	DMA_ClearFlag(WS2812_DMA_TC); // 清除对应的 DMA 传输完成标志位
	
}

/*
*********************************************************************************************************
* 函 数 名: ws2812Send
* 功能说明: 发送一次灯带数据
* 形 参: uint8_t (*color)[3] 是二维数组(按照[0]对应红色数值,[1]对应绿色数值,[2]对应蓝色数值)
* uint16_t len 需要同时操作的灯的数量(注意,不要超过 NBR_LEDS)
* 返 回 值: 无
*********************************************************************************************************
*/
void ws2812Send(uint8_t (*color)[3], uint16_t len)
{
	
	uint16_t i = 0;
	if(len>NBR_LEDS)
	{
		printf("操作的灯数量超出定义\r\n");
		return;
	}
	for(i = 0;i < NBR_LEDS; i++)
	{
		
		if(i<len)
		{
			send_Data_rgb(color[i][0],color[i][1],color[i][2]);  //调换rgb 灯环的颜色顺序导致不同
		}
		else
		{
			send_Data_rgb(0,0,0);//灭剩余的灯 ,注意,黑色的 rgb 为 0,0,0
		}
	}
}



/*
*********************************************************************************************************
* 函 数 名: WS2812_effect
* 功能说明: WS2812 效果
* 形 参: uint8_t effect 效果参数
* 返 回 值: 无
*********************************************************************************************************
*/
void WS2812_effect(uint8_t effect)
{
	uint8_t i=0;
	uint8_t buf[NBR_LEDS][3] = {0};
	for(i=0;i<NBR_LEDS;i++) //填充数值
	{
		buf[i][0] = test_color[effect][0];
		buf[i][1] = test_color[effect][1];
		buf[i][2] = test_color[effect][2];
	}
	ws2812Send(buf,NBR_LEDS); //显示
}



ws2812.h

#ifndef __BSP_WS2812_H
#define __BSP_WS2812_H
#include "sys.h"
/
移植修改区
按照实际端口修改
较前版本更加容易移植(注意,端口仅仅适用于非 JTAG/SWD 引脚,如果是 JTAG 引脚,需要打开 AFIO 时钟,并失能JTAG)
//注意,配合程序仅适用于 TIM2~TIM5 通用定时器

#define WS2812_GPIO_RCC RCC_APB2Periph_GPIOB //端口时钟
#define WS2812_GPIO_Pin GPIO_Pin_6 //引脚号
#define WS2812_GPIO_Port GPIOB //端口号
#define WS2812_TIM_RCC RCC_APB1Periph_TIM4 //定时器时钟

#define WS2812_TIM TIM4 //定时器
#define WS2812_TIM_OCxInit TIM_OC1Init //定时器比较函数
#define WS2812_DMA_RCC RCC_AHBPeriph_DMA1 //DMA 时钟

#define WS2812_DMA_ADDR TIM4->CCR1 //连接的外设基地址
#define WS2812_DMA_CH DMA1_Channel7 //DMAx 通道
#define WS2812_DMA_TC DMA1_FLAG_TC7 //DMAx 传输完成标志

/
#define TIMING_ONE 61 //T1H 1 码 68%占空比 68%*89=61
#define TIMING_ZERO 28 //T0L 0 码 32%占空比 32%*89=28
#define LED_BYTE_Buffer_Size 24 //RGB 共 24
#define NBR_LEDS 12 //WS2812 RGB 灯个数

/* 供外部调用的函数声明 */
void bsp_InitWS2812B(void);

void ws2812Send(uint8_t (*color)[3], uint16_t len);
void WS2812_effect(uint8_t effect);
#endif


RC522.c

#include "bsp.h"
/*
*********************************************************************************************************
* 函 数 名: bsp_InitRc522
* 功能说明: 初始化 RC522 的 IO 口和 SPI 功能配置
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitRc522(void)
{
	SPI_InitTypeDef SPI_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;
	
	
	RCC_APB2PeriphClockCmd( RCC_ALL_RC522, ENABLE ); //RC522 时钟使能
	GPIO_InitStructure.GPIO_Pin = RC522_CS_GPIO_PIN; // RC522_CS 推挽
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(RC522_CS_GPIO_PORT, &GPIO_InitStructure);
	
	
	GPIO_InitStructure.GPIO_Pin = RC522_RST_GPIO_PIN; // RC522_RST 推挽
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(RC522_RST_GPIO_PORT, &GPIO_InitStructure);
	
	
	RC522_CS = 1; //RC522 不选中
	RC522_RST = 1; //RC522 不复位
	bsp_InitSPIx(RC522_SPIx); //初始化 CLK,MISO,MOSI 三个端口和 SPI 时钟
	
	
	/* SPI 模式配置 */
	// FLASH 芯片 支持 SPI 模式 0,据此设置 CPOL CPHA
	SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
	SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
	SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
	SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
	SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
	SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
	
	//SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
	SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
	SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
	SPI_InitStructure.SPI_CRCPolynomial = 7;
	SPI_Init(RC522_SPIx , &SPI_InitStructure);
	/* 使能 SPI */
	SPI_Cmd(RC522_SPIx , ENABLE);
}
/*
*********************************************************************************************************
* 函 数 名: SPI_RC522_SendByte
* 功能说明: 从 SPI 总线写入一个字节
* 形 参: byte:要写入的字节
* 返 回 值: 返回接收到的数据
*********************************************************************************************************
*/
uint8_t SPI_RC522_SendByte(uint8_t byte)
{
	return SPIx_ReadWriteByte(RC522_SPIx,byte);
}
/*
*********************************************************************************************************
* 函 数 名: SPI_RC522_ReadByte
* 功能说明: 从 SPI 总线读取一个字节
* 形 参: 无
* 返 回 值: 读取到的字节
*********************************************************************************************************
*/
uint8_t SPI_RC522_ReadByte(void)
{
	return (SPI_RC522_SendByte(RC522_Dummy_Byte));
}
/*
*********************************************************************************************************
* 函 数 名: ReadRawRC
* 功能说明: 读 RC522 寄存器
* 形 参: Address:寄存器地址
* 返 回 值: 读出的值
*********************************************************************************************************
*/
uint8_t ReadRawRC(uint8_t Address)
{
	uint8_t ucAddr;
	uint8_t ucResult=0;
	ucAddr = ( ( ( Address <<1 ) & 0x7E ) | 0x80 );
	/*选择 RC522: CS 低 */
	/* 通讯开始: CS 低 */
	RC522_CS = 0;
	SPI_RC522_SendByte( ucAddr );
	ucResult = SPI_RC522_ReadByte();
	/* 停止信号 RC522: CS 高 */
	/* 通讯开始: CS 低 */
	RC522_CS = 1;
	return ucResult;
}
/*
*********************************************************************************************************
* 函 数 名: ReadRawRC
* 功能说明: 写 RC522 寄存器
* 形 参: uint8_t Address:寄存器地址
* uint8_t value:写入的值
* 返 回 值: 无
*********************************************************************************************************
*/
void WriteRawRC(uint8_t Address, uint8_t value)
{
	uint8_t ucAddr;
	ucAddr = ( ( Address << 1 ) & 0x7E );
	/*选择 RC522: CS 低 */
	/* 通讯开始: CS 低 */
	RC522_CS = 0;
	SPI_RC522_SendByte( ucAddr );
	SPI_RC522_SendByte( value );
	/* 停止信号 RC522: CS 高 */
	/* 通讯开始: CS 低 */
	RC522_CS = 1;
}
/*
*********************************************************************************************************
* 函 数 名: SetBitMask
* 功能说明: 对 RC522 寄存器置位
* 形 参: uint8_t ucReg,寄存器地址
* uint8_t ucMask,置位值
* 返 回 值: 无
*********************************************************************************************************
*/
void SetBitMask ( uint8_t ucReg, uint8_t ucMask )
{
	uint8_t ucTemp = 0;
	ucTemp = ReadRawRC ( ucReg );
	WriteRawRC ( ucReg, ucTemp | ucMask ); // set bit mask
}
/*
*********************************************************************************************************
* 函 数 名: ClearBitMask
* 功能说明: 对 RC522 寄存器清位
* 形 参: uint8_t ucReg,寄存器地址
* uint8_t ucMask,清位值
* 返 回 值: 无
*********************************************************************************************************
*/
void ClearBitMask ( uint8_t ucReg, uint8_t ucMask )
{
	uint8_t ucTemp = 0;
	ucTemp = ReadRawRC ( ucReg );
	WriteRawRC ( ucReg, ucTemp & ( ~ ucMask) ); // clear bit mask
}
/*
*********************************************************************************************************
* 函 数 名: PcdAntennaOn
* 功能说明: 开启天线
* 形 参: 无
* 返 回 值: 无
* 注 意:每次启动或关闭天险发射之间应至少有 1ms 的间隔
*********************************************************************************************************
*/
void PcdAntennaOn ( void )
{
	uint8_t uc;
	uc = ReadRawRC ( TxControlReg );
	if ( ! ( uc & 0x03 ) )
	{
		SetBitMask( TxControlReg, 0x03 );
	}
}
/*
*********************************************************************************************************
* 函 数 名: PcdAntennaOff
* 功能说明: 关闭天线
* 形 参: 无
* 返 回 值: 无
* 注 意:每次启动或关闭天险发射之间应至少有 1ms 的间隔
*********************************************************************************************************
*/
void PcdAntennaOff ( void )
{
	ClearBitMask ( TxControlReg, 0x03 );
}
/*
*********************************************************************************************************
* 函 数 名: PcdReset
* 功能说明: 复位 RC522
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void PcdReset ( void )
{
	/* 复位 RC522: RST 高 */
	RC522_RST = 1;
	delay_us(10); //_NOP();
	/* 取消复位 RC522: RST 低 */
	RC522_RST = 0;
	delay_us(10); //_NOP();
	/* 复位 RC522: RST 高 */
	RC522_RST = 1;
	delay_us(10); //_NOP();
	WriteRawRC ( CommandReg, 0x0f );
	while ( ReadRawRC ( CommandReg ) & 0x10 );
	delay_us(10); //_NOP();
	WriteRawRC ( ModeReg, 0x3D ); //定义发送和接收常用模式 和 Mifare 卡通讯, CRC 初始值 0x6363
	WriteRawRC ( TReloadRegL, 30 ); //16 位定时器低位
	WriteRawRC ( TReloadRegH, 0 ); //16 位定时器高位
	WriteRawRC ( TModeReg, 0x8D ); //定义内部定时器的设置
	WriteRawRC ( TPrescalerReg, 0x3E ); //设置定时器分频系数
	WriteRawRC ( TxAutoReg, 0x40 ); //调制发送信号为 100%ASK
}
/*
*********************************************************************************************************
* 函 数 名: PcdComMF522
* 功能说明: 通过 RC522 和 ISO14443 卡通讯
* 形 参: ucCommand, RC522 命令字
* pInData,通过 RC522 发送到卡片的数据
* ucInLenByte,发送数据的字节长度
* pOutData,接收到的卡片返回数据
* pOutLenBit,返回数据的位长度
* 返 回 值: 状态值= MI_OK,成功
*********************************************************************************************************
*/
char PcdComMF522 ( uint8_t ucCommand, uint8_t * pInData, uint8_t ucInLenByte, uint8_t * pOutData, uint32_t * pOutLenBit )
{
	char cStatus = MI_ERR;
	uint8_t ucIrqEn = 0x00;
	uint8_t ucWaitFor = 0x00;
	uint8_t ucLastBits;
	uint8_t ucN;
	uint32_t ul;
	switch ( ucCommand )
	{
		case PCD_AUTHENT: //Mifare 认证
		{
			ucIrqEn = 0x12; //允许错误中断请求 ErrIEn 允许空闲中断 IdleIEn
			ucWaitFor = 0x10; //认证寻卡等待时候 查询空闲中断标志位
		}
		break;
		
		case PCD_TRANSCEIVE: //接收发送 发送接收
		{
			ucIrqEn = 0x77; //允许 TxIEn RxIEn IdleIEn LoAlertIEn ErrIEn TimerIEn
			ucWaitFor = 0x30; //寻卡等待时候 查询接收中断标志位与 空闲中断标志位
		}
		break;
		
		default:break;
	}
	
	WriteRawRC ( ComIEnReg, ucIrqEn | 0x80 ); //IRqInv 置位管脚 IRQ 与 Status1Reg 的 IRq 位的值相反
	ClearBitMask ( ComIrqReg, 0x80 ); //Set1 该位清零时, CommIRqReg 的屏蔽位清零
	WriteRawRC ( CommandReg, PCD_IDLE ); //写空闲命令
	SetBitMask ( FIFOLevelReg, 0x80 ); //置位 FlushBuffer 清除内部 FIFO 的读和写指针以及 ErrReg 的BufferOvfl 标志位被清除
	for ( ul = 0; ul < ucInLenByte; ul ++ )
	{
		WriteRawRC ( FIFODataReg, pInData [ ul ] ); //写数据进 FIFOdata
	}
	
	WriteRawRC ( CommandReg, ucCommand ); //写命令
	
	if ( ucCommand == PCD_TRANSCEIVE )
	{
		SetBitMask(BitFramingReg,0x80); //StartSend 置位启动数据发送 该位与收发命令使用时才有效
	}
	ul = 1000;//根据时钟频率调整,操作 M1 卡最大等待时间 25ms
	do //认证 与寻卡等待时间
	{
		ucN = ReadRawRC ( ComIrqReg ); //查询事件中断
		ul --;
	} 
	while ( ( ul != 0 ) && ( ! ( ucN & 0x01 ) ) && ( ! ( ucN & ucWaitFor ) ) ); //退出条件 i=0,定时器中断,与写空闲命令
	ClearBitMask ( BitFramingReg, 0x80 ); //清理允许 StartSend 位
	if ( ul != 0 )
	{
		if ( ! ( ReadRawRC ( ErrorReg ) & 0x1B ) ) // 读 错 误 标 志 寄 存 器 BufferOfI CollErr ParityErrProtocolErr
		{
			cStatus = MI_OK;
			
			if ( ucN & ucIrqEn & 0x01 ) //是否发生定时器中断
			{
				cStatus = MI_NOTAGERR;
			}
			
			if ( ucCommand == PCD_TRANSCEIVE )
			{
				ucN = ReadRawRC ( FIFOLevelReg ); //读 FIFO 中保存的字节数
				ucLastBits = ReadRawRC ( ControlReg ) & 0x07; //最后接收到得字节的有效位数
				if ( ucLastBits )
				{
					* pOutLenBit = ( ucN - 1 ) * 8 + ucLastBits; //N 个字节数减去 1(最后一个字节) +最后一位的位数 读取到的数据总位数
				}
				
				else
				{
					* pOutLenBit = ucN * 8; //最后接收到的字节整个字节有效
				}
				
				if ( ucN == 0 )
				{
					ucN = 1;
				}
				
				if ( ucN > MAXRLEN )
				{
					ucN = MAXRLEN;
				}
				
				for ( ul = 0; ul < ucN; ul ++ )
				{
					pOutData [ ul ] = ReadRawRC ( FIFODataReg );
				}
			}
		}
		
		else
		{
			cStatus = MI_ERR;
		}
	}
	
	SetBitMask ( ControlReg, 0x80 ); // stop timer now
	WriteRawRC ( CommandReg, PCD_IDLE );
	return cStatus;
}
/*
*********************************************************************************************************
* 函 数 名: M500PcdConfigISOType
* 功能说明: 设置 RC522 的工作方式
* 形 参: ucType,工作方式
* 返 回 值: 无
*********************************************************************************************************
*/
void M500PcdConfigISOType ( uint8_t ucType )
{
	if ( ucType == 'A') //ISO14443_A
	{
		ClearBitMask ( Status2Reg, 0x08 );
		
		WriteRawRC ( ModeReg, 0x3D ); //3F
		WriteRawRC ( RxSelReg, 0x86 ); //84
		WriteRawRC( RFCfgReg, 0x7F ); //4F
		WriteRawRC( TReloadRegL, 30 );//tmoLength);// TReloadVal = 'h6a =tmoLength(dec)
		WriteRawRC ( TReloadRegH, 0 );
		WriteRawRC ( TModeReg, 0x8D );
		WriteRawRC ( TPrescalerReg, 0x3E );
		
		delay_us ( 2 );
		PcdAntennaOn ();//开天线
	}
}
/*
*********************************************************************************************************
* 函 数 名: PcdRequest
* 功能说明: 寻卡
* 形 参: ucReq_code,寻卡方式
* = 0x52,寻感应区内所有符合 14443A 标准的卡
* = 0x26,寻未进入休眠状态的卡
* pTagType,卡片类型代码
* = 0x4400, Mifare_UltraLight
* = 0x0400, Mifare_One(S50)
* = 0x0200, Mifare_One(S70)
* = 0x0800, Mifare_Pro(X))
* = 0x4403, Mifare_DESFire
* 返 回 值: 状态值= MI_OK,成功
*********************************************************************************************************
*/
char PcdRequest ( uint8_t ucReq_code, uint8_t * pTagType )
{
	char cStatus;
	uint8_t ucComMF522Buf [ MAXRLEN ];
	uint32_t ulLen;
	ClearBitMask ( Status2Reg, 0x08 ); //清理指示 MIFARECyptol 单元接通以及所有卡的数据通信被加密的情况
	WriteRawRC ( BitFramingReg, 0x07 ); // 发送的最后一个字节的 七位
	SetBitMask ( TxControlReg, 0x03 ); //TX1,TX2 管脚的输出信号传递经发送调制的 13.56 的能量载波信号
	ucComMF522Buf [ 0 ] = ucReq_code; //存入 卡片命令字
	cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 1, ucComMF522Buf, & ulLen ); //寻卡
	if ( ( cStatus == MI_OK ) && ( ulLen == 0x10 ) ) //寻卡成功返回卡类型
	{
		*pTagType = ucComMF522Buf [ 0 ];
		*( pTagType + 1 ) = ucComMF522Buf [ 1 ];
	}
	
	else
	{
		cStatus = MI_ERR;
	}
	return cStatus;
}
/*
*********************************************************************************************************
* 函 数 名: PcdAnticoll
* 功能说明: 防冲撞
* 形 参: pSnr,卡片序列号, 4 字节
* 返 回 值: 状态值= MI_OK,成功
*********************************************************************************************************
*/
char PcdAnticoll ( uint8_t * pSnr )
{
	char cStatus;
	uint8_t uc, ucSnr_check = 0;
	uint8_t ucComMF522Buf [ MAXRLEN ];
	uint32_t ulLen;
	
	ClearBitMask ( Status2Reg, 0x08 ); //清 MFCryptol On 位 只有成功执行 MFAuthent 命令后,该位才能置位
	WriteRawRC ( BitFramingReg, 0x00); //清理寄存器 停止收发
	ClearBitMask ( CollReg, 0x80 ); //清 ValuesAfterColl 所有接收的位在冲突后被清除
	
	ucComMF522Buf [ 0 ] = 0x93; //卡片防冲突命令
	ucComMF522Buf [ 1 ] = 0x20;
	
	cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 2, ucComMF522Buf, & ulLen);//与卡片通信
	if ( cStatus == MI_OK) //通信成功
	{
		for ( uc = 0; uc < 4; uc ++ )
		{
			*( pSnr + uc ) = ucComMF522Buf [ uc ]; //读出 UID
			ucSnr_check ^= ucComMF522Buf [ uc ];
		}
		
		if ( ucSnr_check != ucComMF522Buf [ uc ] )
		{
			cStatus = MI_ERR;
		}
	}
	
	SetBitMask ( CollReg, 0x80 );
	
	return cStatus;
}
/*
*********************************************************************************************************
* 函 数 名: CalulateCRC
* 功能说明: 用 RC522 计算 CRC16
* 形 参:
* pIndata,计算 CRC16 的数组
* ucLen,计算 CRC16 的数组字节长度
* pOutData,存放计算结果存放的首地址
* 返 回 值: 无
*********************************************************************************************************
*/
void CalulateCRC ( uint8_t * pIndata, uint8_t ucLen, uint8_t * pOutData )
{
	uint8_t uc, ucN;
	
	ClearBitMask(DivIrqReg,0x04);
	WriteRawRC(CommandReg,PCD_IDLE);
	SetBitMask(FIFOLevelReg,0x80);
	
	for ( uc = 0; uc < ucLen; uc ++)
	{
		WriteRawRC ( FIFODataReg, * ( pIndata + uc ) );
	}
	
	WriteRawRC ( CommandReg, PCD_CALCCRC );
	uc = 0xFF;
	
	do
	{
		ucN = ReadRawRC ( DivIrqReg );
		uc --;
	} 
	while ( ( uc != 0 ) && ! ( ucN & 0x04 ) );
	
	pOutData [ 0 ] = ReadRawRC ( CRCResultRegL );
	pOutData [ 1 ] = ReadRawRC ( CRCResultRegM );
}
/*
*********************************************************************************************************
* 函 数 名: PcdSelect
* 功能说明: 选定卡片
* 形 参: pSnr,卡片序列号, 4 字节
* 返 回 值: 状态值= MI_OK,成功
*********************************************************************************************************
*/
char PcdSelect ( uint8_t * pSnr )
{
	char ucN;
	uint8_t uc;
	uint8_t ucComMF522Buf [ MAXRLEN ];
	uint32_t ulLen;
	
	ucComMF522Buf [ 0 ] = PICC_ANTICOLL1;
	ucComMF522Buf [ 1 ] = 0x70;
	ucComMF522Buf [ 6 ] = 0;
	
	for ( uc = 0; uc < 4; uc ++ )
	{
		ucComMF522Buf [ uc + 2 ] = * ( pSnr + uc );
		ucComMF522Buf [ 6 ] ^= * ( pSnr + uc );
	}
	
	CalulateCRC ( ucComMF522Buf, 7, & ucComMF522Buf [ 7 ] );
	ClearBitMask ( Status2Reg, 0x08 );
	ucN = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 9, ucComMF522Buf, & ulLen );
	
	if ( ( ucN == MI_OK ) && ( ulLen == 0x18 ) )
	{
		ucN = MI_OK;
	}
	else
	{
		ucN = MI_ERR;
	}
	return ucN;
}
/*
*********************************************************************************************************
* 函 数 名: PcdSelect
* 功能说明: 验证卡片密码
* 形 参:
* ucAuth_mode,密码验证模式
* = 0x60,验证 A 密钥
* = 0x61,验证 B 密钥
* ucAddr,块地址
* pKey,密码
* pSnr,卡片序列号, 4 字节
* 返 回 值: 状态值= MI_OK,成功
*********************************************************************************************************
*/
char PcdAuthState ( uint8_t ucAuth_mode, uint8_t ucAddr, uint8_t * pKey, uint8_t * pSnr )
{
	char cStatus;
	uint8_t uc, ucComMF522Buf [ MAXRLEN ];
	uint32_t ulLen;
	
	ucComMF522Buf [ 0 ] = ucAuth_mode;
	ucComMF522Buf [ 1 ] = ucAddr;
	
	for ( uc = 0; uc < 6; uc ++ )
	{
		ucComMF522Buf [ uc + 2 ] = * ( pKey + uc );
	}
	
	for ( uc = 0; uc < 6; uc ++ )
	{
		ucComMF522Buf [ uc + 8 ] = * ( pSnr + uc );
	}
	
	cStatus = PcdComMF522 ( PCD_AUTHENT, ucComMF522Buf, 12, ucComMF522Buf, & ulLen );
	
	if ( ( cStatus != MI_OK ) || ( ! ( ReadRawRC ( Status2Reg ) & 0x08 ) ) )
	{
		cStatus = MI_ERR;
	}
	return cStatus;
}
/*
*********************************************************************************************************
* 函 数 名: PcdWrite
* 功能说明: 写数据到 M1 卡一块
* 形 参:
* ucAddr,块地址
* pData,写入的数据, 16 字节
* 返 回 值: 状态值= MI_OK,成功
*********************************************************************************************************
*/
char PcdWrite ( uint8_t ucAddr, uint8_t * pData )
{
	char cStatus;
	uint8_t uc, ucComMF522Buf [ MAXRLEN ];
	uint32_t ulLen;
	
	ucComMF522Buf [ 0 ] = PICC_WRITE;
	ucComMF522Buf [ 1 ] = ucAddr;
	CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
	cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
	
	if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
	{
		cStatus = MI_ERR;
	}
	
	if ( cStatus == MI_OK )
	{
		//memcpy(ucComMF522Buf, pData, 16);
		for ( uc = 0; uc < 16; uc ++ )
		{
			ucComMF522Buf [ uc ] = * ( pData + uc );
		}
		
		CalulateCRC ( ucComMF522Buf, 16, & ucComMF522Buf [ 16 ] );
		cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 18, ucComMF522Buf, & ulLen );
		
		if ( ( cStatus != MI_OK ) || ( ulLen != 4 ) || ( ( ucComMF522Buf [ 0 ] & 0x0F ) != 0x0A ) )
		{
			cStatus = MI_ERR;
		}
	}
	return cStatus;
}
/*
*********************************************************************************************************
* 函 数 名: PcdRead
* 功能说明: 读取 M1 卡一块数据
* 形 参:
* ucAddr,块地址
* pData,读出的数据, 16 字节
* 返 回 值: 状态值= MI_OK,成功
*********************************************************************************************************
*/
char PcdRead ( uint8_t ucAddr, uint8_t * pData )
{
	char cStatus;
	uint8_t uc, ucComMF522Buf [ MAXRLEN ];
	uint32_t ulLen;
	
	ucComMF522Buf [ 0 ] = PICC_READ;
	ucComMF522Buf [ 1 ] = ucAddr;
	
	CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );	
	cStatus = PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
	if ( ( cStatus == MI_OK ) && ( ulLen == 0x90 ) )
	{
		for ( uc = 0; uc < 16; uc ++ )
		*( pData + uc ) = ucComMF522Buf [ uc ];
	}
	
	else
	{
		cStatus = MI_ERR;
	}
	
	return cStatus;
}
/*
*********************************************************************************************************
* 函 数 名: PcdHalt
* 功能说明: 命令卡片进入休眠状态
* 形 参: 无
* 返 回 值: 状态值= MI_OK,成功
*********************************************************************************************************
*/
char PcdHalt( void )
{
	uint8_t ucComMF522Buf [ MAXRLEN ];
	uint32_t ulLen;
	
	ucComMF522Buf [ 0 ] = PICC_HALT;
	ucComMF522Buf [ 1 ] = 0;
	
	CalulateCRC ( ucComMF522Buf, 2, & ucComMF522Buf [ 2 ] );
	PcdComMF522 ( PCD_TRANSCEIVE, ucComMF522Buf, 4, ucComMF522Buf, & ulLen );
	
	return MI_OK;
}
/***************************** 德致伦电子 DeZLinc (END OF FILE) *********************************/

RC522.h

#ifndef __BSP_RC522_H
#define __BSP_RC522_H
#include "sys.h"
/****************************************************************************/
#define RCC_ALL_RC522 ( RC522_CS_GPIO_CLK | RC522_RST_GPIO_CLK )
#define RC522_CS_GPIO_PIN GPIO_Pin_6 								//RC522_CS 引脚号
#define RC522_CS_PIN_ID 6 											//RC522_CS 引脚序号
#define RC522_CS_GPIO_PORT GPIOF 									//RC522_CS 端口号
#define RC522_CS_GPIO_CLK RCC_APB2Periph_GPIOF						//RC522_CS 时钟
#define RC522_CS_FUN_OUT PFout 										//RC522_CS 输出端口配置函数
//#define RC522_CS_FUN_IN PFin 										//RC522_CS 输入端口配置函数
#define RC522_RST_GPIO_PIN GPIO_Pin_7 								//RC522_RST 引脚号
#define RC522_RST_PIN_ID 7 											//RC522_RST 引脚序号
#define RC522_RST_GPIO_PORT GPIOB 									//RC522_RST 端口号
#define RC522_RST_GPIO_CLK RCC_APB2Periph_GPIOB 					//RC522_RST 时钟
#define RC522_RST_FUN_OUT PBout 									//RC522_RST 输出端口配置函数
//#define RC522_CS_FUN_IN PBin 										//RC522_RST 输入端口配置函数
#define RC522_SPIx SPI1 											//RC522 使用 SPI1 端口
/****************************************************************************/
//IO 操作函数
#define RC522_CS RC522_CS_FUN_OUT(RC522_CS_PIN_ID) 					//RC522_CS RC522 的片选信号
#define RC522_RST RC522_RST_FUN_OUT(RC522_RST_PIN_ID) 				//RC522_RST RC522 的复位信号

/
//MF522 命令字
/
#define PCD_IDLE 0x00 												//取消当前命令
#define PCD_AUTHENT 0x0E 											//验证密钥
#define PCD_RECEIVE 0x08 											//接收数据
#define PCD_TRANSMIT 0x04 											//发送数据
#define PCD_TRANSCEIVE 0x0C 										//发送并接收数据
#define PCD_RESETPHASE 0x0F 										//复位
#define PCD_CALCCRC 0x03 											//CRC 计算
/
//Mifare_One 卡片命令字
/
#define PICC_REQIDL 0x26 											//寻天线区内未进入休眠状态
#define PICC_REQALL 0x52 											//寻天线区内全部卡
#define PICC_ANTICOLL1 0x93 										//防冲撞
#define PICC_ANTICOLL2 0x95 										//防冲撞
#define PICC_AUTHENT1A 0x60 										//验证 A 密钥
#define PICC_AUTHENT1B 0x61 										//验证 B 密钥
#define PICC_READ 0x30 												//读块
#define PICC_WRITE 0xA0 											//写块
#define PICC_DECREMENT 0xC0 										//扣款
#define PICC_INCREMENT 0xC1 										//充值
#define PICC_RESTORE 0xC2 											//调块数据到缓冲区
#define PICC_TRANSFER 0xB0 											//保存缓冲区中数据
#define PICC_HALT 0x50 												//休眠
/
//MF522 FIFO 长度定义
/
#define DEF_FIFO_LENGTH 64 //FIFO size=64byte
#define MAXRLEN 18
/
//MF522 寄存器定义
/


// PAGE 0
#define RFU00 0x00
#define CommandReg 0x01
#define ComIEnReg 0x02
#define DivlEnReg 0x03
#define ComIrqReg 0x04
#define DivIrqReg 0x05
#define ErrorReg 0x06
#define Status1Reg 0x07
#define Status2Reg 0x08
#define FIFODataReg 0x09
#define FIFOLevelReg 0x0A
#define WaterLevelReg 0x0B
#define ControlReg 0x0C
#define BitFramingReg 0x0D
#define CollReg 0x0E
#define RFU0F 0x0F


// PAGE 1
#define RFU10 0x10
#define ModeReg 0x11
#define TxModeReg 0x12
#define RxModeReg 0x13
#define TxControlReg 0x14
#define TxAutoReg 0x15
#define TxSelReg 0x16
#define RxSelReg 0x17
#define RxThresholdReg 0x18
#define DemodReg 0x19
#define RFU1A 0x1A
#define RFU1B 0x1B
#define MifareReg 0x1C
#define RFU1D 0x1D
#define RFU1E 0x1E
#define SerialSpeedReg 0x1F


// PAGE 2
#define RFU20 0x20
#define CRCResultRegM 0x21
#define CRCResultRegL 0x22
#define RFU23 0x23
#define ModWidthReg 0x24
#define RFU25 0x25
#define RFCfgReg 0x26
#define GsNReg 0x27
#define CWGsCfgReg 0x28
#define ModGsCfgReg 0x29
#define TModeReg 0x2A
#define TPrescalerReg 0x2B
#define TReloadRegH 0x2C
#define TReloadRegL 0x2D
#define TCounterValueRegH 0x2E
#define TCounterValueRegL 0x2F


// PAGE 3
#define RFU30 0x30
#define TestSel1Reg 0x31
#define TestSel2Reg 0x32
#define TestPinEnReg 0x33
#define TestPinValueReg 0x34
#define TestBusReg 0x35
#define AutoTestReg 0x36
#define VersionReg 0x37
#define AnalogTestReg 0x38
#define TestDAC1Reg 0x39
#define TestDAC2Reg 0x3A
#define TestADCReg 0x3B
#define RFU3C 0x3C
#define RFU3D 0x3D
#define RFU3E 0x3E
#define RFU3F 0x3F


/
//和 MF522 通讯时返回的错误代码
/
#define MI_OK 0x26
#define MI_NOTAGERR 0xcc
#define MI_ERR 0xbb
#define RC522_Dummy_Byte 0xFF

/* 供外部调用的函数声明 */
void bsp_InitRc522(void);
void PcdReset ( void ); 												//复位
void M500PcdConfigISOType ( u8 type ); 									//工作方式
char PcdRequest ( u8 req_code, u8 * pTagType ); 						//寻卡
char PcdAnticoll ( u8 * pSnr); 											//读卡号
char PcdAuthState ( u8 ucAuth_mode, u8 ucAddr, u8 * pKey, u8 * pSnr );  //验证卡片密码
char PcdRead ( u8 ucAddr, u8 * pData ); 								//读卡
char PcdSelect ( u8 * pSnr );										    //选卡
char PcdHalt( void );

#endif

上位机部分
在这里插入图片描述
主界面

using System;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Wisdomclassroom
{
    public partial class Main : Form
    {

        SerialClass sc;
        SQL sql;

        String wendu;



        public Main()
        {
            this.StartPosition = FormStartPosition.CenterScreen;
            InitializeComponent();
        }


        private void Main_Load(object sender, EventArgs e)
        {

            /*串口部分 */
            sc = new SerialClass("COM10", 9600);
            sc.openPort();
            sc.ReadData = Read1;
            
            /*连接数据库*/
            sql = new SQL("11.111.11.11", "xxxx", "xxx", "xxxxx");
            sql.Connect();

            /* 天气 API外接   json解析*/
            string str = API.PostWebRequest("http://apis.juhe.cn/simpleWeather/query", "city=%E5%A4%A9%E6%B4%A5&key=xxxxx");
            JObject json1 = JObject.Parse(str);//解析json Newtonsoft.Json.Linq.JObject class.
            string jieguo = json1["reason"].ToString();
            wendu = json1["result"]["realtime"]["temperature"].ToString();
            string info = json1["result"]["realtime"]["info"].ToString();
            string humidity = json1["result"]["realtime"]["humidity"].ToString();
           temp .Text = wendu;
           weather.Text = info;
           hum.Text  = humidity;


            int a = Convert.ToInt32(wendu);

            if (numericUpDown1.Value < a)
            {
                bo = true;
                byte[] data = { 0x05 };
                sc.SendData(data);
            }
            else 
            {
                bo = false;
                byte[] data = { 0x06 };
                sc.SendData(data);
          }

            /*启动time控件 */
            timer1.Start();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            /*显示系统时间、日期 */
            calendar.Text = DateTime.Now.ToString("yyy年MM月dd日");
            time.Text = DateTime.Now.ToString("HH时mm分ss秒");
        }

        public void Read(string readstr, byte[] temp)
        {   
                //byte[] data = { 0x05 };
                //sc.SendData(data);
                /* 下位机体温部分 */
            Invoke(new MethodInvoker(delegate ()
            {            
                //label1.Text = readstr+"°C";
               // MessageBox.Show(byteToHexStr(temp));
               //do something... 
            }));
        }

        public void Read1(string readstr, byte[] card)
        {
            /*读取数据库的数据 ,刷卡显示信息*/
            string xingming = sql.GetString(string.Format("select xingming from [login] where ID='{0}'", card));

            string arr = byteToHexStr(card);
            string sr = sql.GetString("select ID from [login] where ID='" + arr + "'");
            if (sr != "")
            {
                string id = sql.GetString("select ID from [login] where ID='" + arr + "'");
                string xm = sql.GetString("select xingming from [login] where ID='" + arr + "'");
                string xb = sql.GetString("select xingbie from [login] where ID='" + arr + "'");
                string xj = sql.GetString("select xueji from [login] where ID='" + arr + "'");

                MessageBox.Show("姓名:" + xm + '\n' + "性别:" + xb + '\n' + "学籍校:" + xj + '\n' + "ID:" + id+'\n'+"已打卡");
            }
            else
            {
                MessageBox.Show("卡号不存在");
            }
        }

        public string byteToHexStr(byte[] bytes)
        {
            //字节数组转16进制字符串 
            string returnStr = "";
            if (bytes != null)
            {
                for (int i = 0; i < bytes.Length; i++)
                {
                    returnStr += bytes[i].ToString("X2");
                }
            }
            return returnStr;
        }
        private void Main_Activated(object sender, EventArgs e)
        {
            /*RFID刷卡、打开串口*/
            sc = new SerialClass("COM10", 9600);
            sc.openPort();
            sc.ReadData = Read1;
        }

        private void openled_Click(object sender, EventArgs e)
        {
            /* 开下位机灯  */
            // byte[] data = { 0xfd, 0x03, 0x07, 0x04, 0x01, 0x60, 0xdf };
            byte[] data = { 0x03 };
            sc.SendData(data);
            MessageBox.Show("教室灯光已开");
        }

        private void panel3_Click(object sender, EventArgs e)
        {
            /* 关下位机灯  */
          //  byte[] data = { 0xfd, 0x03, 0x07, 0x04, 0x02, 0x60, 0xdf };
             byte[] data = { 0x04};
             sc.SendData(data);
            MessageBox.Show("教室灯光已关");
        }

        private void panel2_MouseUp(object sender, MouseEventArgs e)
        {
            //效果:按下颜色变暗
        }

        private void panel4_Click(object sender, EventArgs e)
        {

            /*温度阈值判断,温度大于阈值开下位机风扇,温度小于阈值关风扇*/

            int a = Convert.ToInt32(wendu);
            if (numericUpDown1.Value < a)
            {
                byte[] data = { 0x05 };
                sc.SendData(data);
                MessageBox.Show("风扇已开");
            }
            else
            {
                byte[] data = { 0x06 };
                sc.SendData(data);
                MessageBox.Show("温度低于阈值");             
            }
        }



        private void Media_off_Click(object sender, EventArgs e)
        {
            //关下位机风扇
            byte[] data = { 0x06 };
            sc.SendData(data);
            MessageBox.Show("风扇已关");
        }


        private void panel5_Click(object sender, EventArgs e)
        {
            //开下位机蜂鸣器
            byte[] data = { 0x07 };
            sc.SendData(data);
            MessageBox.Show("音箱已开");
        }

        private void panel6_Click(object sender, EventArgs e)
        {
            //开下位机舵机
            byte[] data = { 0x01};
            sc.SendData(data);
            MessageBox.Show("教室窗户已开");
        }

        private void win_off_Click(object sender, EventArgs e)
        {
            //关下位机舵机
            byte[] data = { 0x02 };
            sc.SendData(data);
            MessageBox.Show("教室窗户已关");
        }

        private void beep_off_Click(object sender, EventArgs e)
        {
            //关下位机蜂鸣器
            byte[] data = {0x08};
            sc.SendData(data);
        }


        private void panel1_Click(object sender, EventArgs e)
        {
            /* 跳转表单 退出线程 */
            Form f1 = new DataSheet();
            this.Hide();
            f1.ShowDialog();
            Application.ExitThread();
        }


        /**/
        private void panel5_Click_1(object sender, EventArgs e)
        {
            /*跳转登录 退出线程*/
            Form f = new denglu();
            this.Hide();
            f.ShowDialog();
            Application.ExitThread();
        }

        private void Main_Deactivate(object sender, EventArgs e)
        {
            sc.closePort();
        }

        private void Main_Activated_1(object sender, EventArgs e)
        {
            sc.openPort();
        }


        bool bo;
        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {

            /*温度阈值判断,温度大于阈值开下位机风扇,温度小于阈值关风扇*/
            
            int a = Convert.ToInt32(wendu);
            if (numericUpDown1.Value < a)
            {
                byte[] data = { 0x05 };
                sc.SendData(data);
                if (bo==false)
                { 
                   MessageBox.Show("温度高于阈值,风扇已开");
                    bo = true;
                }
        
            }
            else
            {
                byte[] data = { 0x06 };
                sc.SendData(data);
                if (bo == true)
                { 
                   MessageBox.Show("温度低于阈值,风扇已关闭");
                    bo = false;
                    byte[] data1 = { 0x07 };
                    sc.SendData(data1);
                }
                
            }
        }
    }
}

表单部分
在这里插入图片描述

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.IO;

namespace Wisdomclassroom
{
    
    public partial class DataSheet : Form
    {
        SQL sql;
        public DataSheet()
        {
            this.StartPosition = FormStartPosition.CenterScreen;
            InitializeComponent();
        }

        private void DataSheet_Load(object sender, EventArgs e)
        {

            sql = new SQL("11.111.11.11", "xxxxxx", "xxx", "xxxxx");
            sql.Connect();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            string connstr = @"Data Source=11.111.11.11;Initial Catalog=xxxxxx;Uid=xxx;Pwd=xxxxx";
            saveFileDialog1.Filter = "文本文件|*.txt";
            if (saveFileDialog1.ShowDialog() == DialogResult.OK)
            {
                string path = saveFileDialog1.FileName;
                using (SqlConnection conn = new SqlConnection(connstr))
                {
                    
                    string sql1 = "select xingming,ID,xueji from [login]";
                    using (SqlCommand cmd = new SqlCommand(sql1, conn))
                    {

                         conn.Open();
                        using (SqlDataReader dr = cmd.ExecuteReader())
                        {
                            List<string> student = new List<string>();
                            while (dr.Read())
                            {
                                string num = dr["ID"].ToString();
                                string name = dr["xingming"].ToString();
                                string school = dr["xueji"].ToString();
                                student.Add( "姓名:"+name+ "  "+"学号:"+num+"   "+"学籍校:"+ school) ;
                            }
                            File.WriteAllLines(path, student.ToArray());
                            MessageBox.Show("导出成功");
                        }
                    }
                }
            }
        }

        private denglu anotherForm;
        private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            anotherForm = new denglu();
            this.Hide();
            anotherForm.ShowDialog();
            Application.ExitThread();
        }

        private zhuce anotherForm1;
        private void 个人信息录入ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            anotherForm1 = new zhuce();
            this.Hide();
            anotherForm1.ShowDialog();
            Application.ExitThread();
        }

        private wangjimima anotherForm2;
        private void 修改密码ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            anotherForm2 = new wangjimima();
            this.Hide();
            anotherForm2.ShowDialog();
            Application.ExitThread();
        }

        private void 清空数据库ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            String str = sql.GetString("delete from [login]");
            MessageBox.Show("数据库已清空");
        }
    }
}

总结:

由于本项目应用到了硬件,主要通过串口将上位机C#和下位机stm32进行通信,上位机通过发送协议数据给下位机,数据传输完成,下位机判断不同的数据,响应执行串口中断函数,实现不同的功能。而串口通信在传输协议里并不是最优的选择,所以我想在以后项目用到Wi-Fi或Zigbee协议等,来提升自己的水平。

技术问题:

硬件层面上:

项目初期,在实现单独人体红外测温模块,下位机能够正常响应,能够接收到正常温度的发送。

项目中期阶段,其他外设的加入,导致硬件引脚的冲突,例如下位机板载的灯环用到了PB6引脚及RFID模块的PB7引脚,在板载外设不能更改的情况下,先是将红外测温模块底层代码的数据线和时钟线引脚进行修改,但还是读不到正确的温度。

项目后期阶段,在保证核心功能RFID的实现下,权衡将红外模块去除,加入执行器风扇,通过和阈值温度的判断,实现自动开关,其也是较为创新的地方。

软件层面上:

C#核心问题:

在上位机C#在项目快结束时一直存在的问题,其下位机RFID,通过串口将电子标签的ID发送给上位机,上位机里的串口类,当接收到一个字节时,也会触发DataReceived事件,同时调用Invoke函数,将卡号显示的textbox里,其只有第一次刷的卡号才能显示,再刷传输来的数据就会溢出或不正确。
经过老师指导,在每次的刷卡之后接收到数据,可以用clear将上次传过来的数据清除,保证每次的数据帧的正确,但这个串口类调用不了clear,所以转换思路,通过设置缓存区的方式,将传过来的数据的帧头和结束符做一个判断,将其放入线程里,将其实现数据的传输的正确性。
问题解决思路的不同,也导致项目后期工作量不同、业务逻辑不同。后来在下位机中,将电子标签一靠近RFID,就会一直读改为读一次。最后也是通过简单的方法解决复杂的问题。

可加本人Q1429536866,欢迎大家指导讨论。

标签:TIM,void,教室,控制系统,智能,RC522,uint8,GPIO,define
来源: https://blog.csdn.net/qq_47382085/article/details/118295232

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有