关键代码:
usart2.c
/**
* @brief USART2 初始化
* @param baud: 波特率设置
* @retval None
*/
void USART2_Init(uint32_t baud)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOG,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); // 使能 USART2 时钟
/* USART2 引脚复用映射 */
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); //PA2 复用为 USART2
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); //PA3 复用为 USART2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; //PA2 与 PA3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Fast_Speed; // 速度 50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉
GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置生效
//PG8 推挽输出 , 用于 RS-485 模式控制
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //PG8
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; // 输出
GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed; // 速度 100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉
GPIO_Init(GPIOG, &GPIO_InitStructure); // 配置生效
/* USART2 初始化设置 */
USART_InitStructure.USART_BaudRate = baud; // 波特率设置
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长 8bit
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(USART2, &USART_InitStructure); // 配置生效
USART_Cmd(USART2, ENABLE); // 使能 USART2
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 开启接收中断
USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); // 开启空闲中断
/* USART2 NVIC 配置 */
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
RS485_RX_MODE; // 默认为接收模式
}
/**
* @brief USART2 发送一个字节
* @param ch: 要发送的字节数据
* @retval None
*/
void USART2_SendByte(uint8_t ch)
{
/* 发送一个字节数据到 USART2 */
USART_SendData(USART2, ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
}
/**
* @brief USART2 发送一个字符串
* @param *str: 要发送的字符串
* @param strlen: 字符串长度
* @retval None
*/
void USART2_SendString(uint8_t *str, uint8_t strlen)
{
unsigned int k = 0;
RS485_TX_MODE; // 进入发送模式
do
{
USART2_SendByte(*(str + k));
} while (k++ < strlen);
RS485_RX_MODE; // 进入接收模式
}
/**
* @brief USART2 中断服务函数
* @param None
* @retval None
*/
void USART2_IRQHandler(void)
{
uint8_t Res, forclear;
if (USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
Res = USART_ReceiveData(USART2);
USART2_RX_Buffer[USART2_RX_Index++] = Res;
/* 防止接收缓存下标溢出 */
if (USART2_RX_Index >= USART2_RX_MAX)
USART2_RX_Index = 0;
}
if (USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)
{
USART2_RX_OverFlag = 1;
forclear = USART_ReceiveData(USART2);
}
}
main.c
int main(void)
{
delay_init(168); // 延时函数初始化
LED_Init(); //LED 端口初始化
Key_Init(); // 按键端口初始化
EXTIx_Init(); // 外部中断初始化
USART1_Init(115200); //USART1 初始化
USART2_Init(115200); //USART2 初始化
DHT11_Init(); //DHT11 初始化
SPI2_Init(); //SPI2 外设初始化
OLED_Init(); //OLED 显示模块初始化
#ifdef SLAVE_DEV
while (DHT11_Init()) // 等待 DHT11 初始化完成
{
printf("DHT11 Init Error!\r\n");
delay_ms(500);
}
printf("DHT11 Init Success!\r\n");
#endif
while (1)
{
count++;
#ifdef SLAVE_DEV
if (data_upload_flag == 1) // 上报标志位为 1
{
if (count >= 200)
{
count = 0;
/* 读取 DHT11 的温湿度值 */
DHT11_Read_Data(&temperature, &humidity);
/* 组合需要显示的信息 */
data_feedback[0] = temperature;
data_feedback[1] = humidity;
buildFeedbackFrame(data_feedback, 2, 0x01, full_data_feedback);
USART2_SendString(full_data_feedback,strlen((const char *)full_data_feedback));
}
}
#endif
#ifdef MASTER_DEV
if (keyValue == KEY_D_PRESS) // 下键按下
{
keyValue = 0;
arrayLength = \
sizeof(cmd_upload_th)/sizeof(cmd_upload_th[0]);
USART2_SendString(cmd_upload_th, arrayLength);
}
else if (keyValue == KEY_U_PRESS) // 上键按下
{
keyValue = 0;
arrayLength = \
sizeof(cmd_stop_upload_th) / sizeof(cmd_stop_upload_th[0]);
USART2_SendString(cmd_stop_upload_th, arrayLength);
}
else if (keyValue == KEY_L_PRESS)// 左键按下
{
keyValue = 0;
arrayLength = \
sizeof(cmd_toggle_led) / sizeof(cmd_toggle_led[0]);
USART2_SendString(cmd_toggle_led, arrayLength);
}
#endif
/* 一帧数据接收完毕 */
if (USART2_RX_OverFlag == 1)
{
USART2_RX_OverFlag = 0;
USART2_RX_Index = 0;
cmd_rs485 = CMD_None;
if (isCheckSumOK(USART2_RX_Buffer) == true)
{
/* 先清空数据帧结构体数据域 */
memset(dataFrame_rs485.data, 0, 8);
/* 解析源数据 */
analysisDataFrame(USART2_RX_Buffer);
/* 判断命令类型 */
cmd_rs485 = getCommandType(&dataFrame_rs485);
}
#ifdef MASTER_DEV
/* 上报温湿度数据命令 */
if (cmd_rs485 == CMD_UPLOAD_TH)
{
/* OLED 显示温湿度 */
temperature = dataFrame_rs485.data[0];
humidity = dataFrame_rs485.data[1];
sprintf(tempString, "Temp:%d", temperature);
sprintf(humiString, "Humi:%d", humidity);
Show_TempHumiLight(); //OLED 显示温湿度数据
}
/* 翻转 LED 命令 */
else if (cmd_rs485 == CMD_TOGGLE_LED)
{
/* OLED 显示 LED 状态 | 亮: 2 ,灭: 3 */
printf("led state\r\n");
if (dataFrame_rs485.data[0] == 3)
{
sprintf(ledString, "LED:OFF");
}
else if (dataFrame_rs485.data[0] == 2)
{
sprintf(ledString, "LED: ON");
}
OLED_Display_String(20, 48, ledString, 16);
}
#endif
#ifdef SLAVE_DEV
/* 上报温湿度数据命令 */
if (cmd_rs485 == CMD_UPLOAD_TH)
{
data_upload_flag = 1;
}
/* 停止上报温湿度数据命令 */
else if (cmd_rs485 == CMD_STOP_UPLOAD_TH)
{
data_upload_flag = 0;
}
/* 翻转 LED 命令 */
else if (cmd_rs485 == CMD_TOGGLE_LED)
{
LED0 = ~LED0;
/* LED 状态 | 亮: 2 ,灭: 3 */
data_feedback[0] = GPIO_ReadInputDataBit(GPIOF, \
GPIO_Pin_9) + 2;
/* 反馈 LED 状态至通信主机 */
buildFeedbackFrame(data_feedback, 1, 0x03, \
full_data_feedback);
USART2_SendString(full_data_feedback, \
strlen((char *)full_data_feedback));
}
#endif
/* 用完清空 USART2 接收缓存 */
memset(USART2_RX_Buffer, 0, 255);
}
if (count % 50 == 0)
LED1 = ~LED1;
delay_ms(10);
}
}
/**
* @brief 获取收到的命令类型
* @param *dataFrame :数据帧结构体首地址
* @retval Command_EnumDef :命令的枚举类型
*/
Command_EnumDef getCommandType(DataFrame_TypeDef *dataFrame)
{
switch (dataFrame->cmd) {
case 1:// 上报温湿度数据
return CMD_UPLOAD_TH;
case 2:// 停止上报温湿度数据
return CMD_STOP_UPLOAD_TH;
case 3:// 翻转 LED
return CMD_TOGGLE_LED;
default:
break;
}
return CMD_None;
}
/**
* @brief 检测数据帧校验和是否正确
* @param *rcvbuf : USART2 接收的数据缓存
* @retval bool : true 校验和正确 | false 校验和错误
*/
bool isCheckSumOK(uint8_t *rcvbuf)
{
uint8_t checkSum = 0, index = 0, tempLength = 0;
tempLength = rcvbuf[3];// 取出帧数据长度
/* 判断帧起始,帧结束,校验和是否正确 */
if(((rcvbuf[0]==0x55)&&(rcvbuf[5+tempLength]==0x0B))||((rcvbuf[0]==0xAA)&&(rcvbuf[5+tempLength]==0x0C)))
{
checkSum=rcvbuf[1]+rcvbuf[2]+rcvbuf[3];
while(tempLength--)
{
checkSum +=*(rcvbuf+4+index);
index++;
}
checkSum=checkSum%256;//保留低8位
}
if(checkSum==*(rcvbuf+4+index))
return true;
return false;
}
void analysisDataFrame(uint8_t *rcvbuf)
{
uint8_t index = 0, dataLength = 0;
dataLength=rcvbuf[3];
dataFrame_rs485.sof=rcvbuf[0];
dataFrame_rs485.dstAddr=rcvbuf[1];
dataFrame_rs485.cmd=rcvbuf[2];
dataFrame_rs485.dataLen=rcvbuf[3];
while(dataLength--)
{
dataFrame_rs485.data[index]=*(rcvbuf+4+index);
index++;
}
dataFrame_rs485.checkSum=*(rcvbuf+4+index);
dataFrame_rs485.eof=*(rcvbuf+5+index);
}
void buildFeedbackFrame(uint8_t *dataFb, uint8_t length, \
uint8_t cmd, uint8_t *full_dataFb)
{
uint8_t index = 0, tempLength = 0;
full_dataFb[0] = 0xAA;
full_dataFb[1] = masterAddr;
full_dataFb[2] = cmd;
full_dataFb[3] = length;
tempLength = length;
full_dataFb[4 + length] = full_dataFb[1] + full_dataFb[2] + \
full_dataFb[3];
while (tempLength--)
{
full_dataFb[4 + index] = *(dataFb + index);
full_dataFb[4 + length] += *(dataFb + index); // 计算 checkSum 值
index++;
}
full_dataFb[5 + length] = 0x0C;
}
/**
* @brief OLED 显示环境参数 ( 温度 / 湿度 )
* @param None
* @retval None
*/
void Show_TempHumiLight(void)
{
OLED_Display_String(20, 0, "RS-485", 16);
OLED_Display_String(20, 16, tempString, 16);
OLED_Display_String(20, 32, humiString, 16);
}