day31:Java和STM32的串口通信
Java向串口发送数据,STM32读取串口的数据,由此来控制LED灯的亮灭,蜂鸣器的启闭。

STM32代码:
工程结构:

bsp_usart.h
#ifndef __USART_H
#define __USART_H
#include "stm32f10x.h"
#include <stdio.h>
/**
* 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏
* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线
* 2-修改GPIO的宏
*/
// 串口1-USART1
#define DEBUG_USARTx USART1
#define DEBUG_USART_CLK RCC_APB2Periph_USART1
#define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_BAUDRATE 115200
// USART GPIO 引脚宏定义
#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
#define DEBUG_USART_TX_GPIO_PORT GPIOA
#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9
#define DEBUG_USART_RX_GPIO_PORT GPIOA
#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10
#define DEBUG_USART_IRQ USART1_IRQn
#define DEBUG_USART_IRQHandler USART1_IRQHandler
// 串口2-USART2
//#define DEBUG_USARTx USART2
//#define DEBUG_USART_CLK RCC_APB1Periph_USART2
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
//// USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOA
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_2
//#define DEBUG_USART_RX_GPIO_PORT GPIOA
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_3
//#define DEBUG_USART_IRQ USART2_IRQn
//#define DEBUG_USART_IRQHandler USART2_IRQHandler
// 串口3-USART3
//#define DEBUG_USARTx USART3
//#define DEBUG_USART_CLK RCC_APB1Periph_USART3
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
//// USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOB)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOB
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
//#define DEBUG_USART_RX_GPIO_PORT GPIOB
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
//#define DEBUG_USART_IRQ USART3_IRQn
//#define DEBUG_USART_IRQHandler USART3_IRQHandler
// 串口4-UART4
//#define DEBUG_USARTx UART4
//#define DEBUG_USART_CLK RCC_APB1Periph_UART4
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
//// USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOC
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_10
//#define DEBUG_USART_RX_GPIO_PORT GPIOC
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_11
//#define DEBUG_USART_IRQ UART4_IRQn
//#define DEBUG_USART_IRQHandler UART4_IRQHandler
// 串口5-UART5
//#define DEBUG_USARTx UART5
//#define DEBUG_USART_CLK RCC_APB1Periph_UART5
//#define DEBUG_USART_APBxClkCmd RCC_APB1PeriphClockCmd
//#define DEBUG_USART_BAUDRATE 115200
//// USART GPIO 引脚宏定义
//#define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOD)
//#define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd
//
//#define DEBUG_USART_TX_GPIO_PORT GPIOC
//#define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_12
//#define DEBUG_USART_RX_GPIO_PORT GPIOD
//#define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_2
//#define DEBUG_USART_IRQ UART5_IRQn
//#define DEBUG_USART_IRQHandler UART5_IRQHandler
void USART_Config(void);
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx, char *str);
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch);
#endif /* __USART_H */
bsp_usart.c
/**
******************************************************************************
* @file bsp_usart.c
* @author fire
* @version V1.0
* @date 2013-xx-xx
* @brief 重定向c库printf函数到usart端口
******************************************************************************
* @attention
*
* 实验平台:秉火STM32 F103-MINI 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
******************************************************************************
*/
#include "bsp_usart.h"
/**
* @brief 配置嵌套向量中断控制器NVIC
* @param 无
* @retval 无
*/
static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* 嵌套向量中断控制器组选择 */
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
/* 配置USART为中断源 */
NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ;
/* 抢断优先级*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
/* 子优先级 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
/* 使能中断 */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
/* 初始化配置NVIC */
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief USART GPIO 配置,工作参数配置
* @param 无
* @retval 无
*/
void USART_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
// 打开串口GPIO的时钟
DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
// 打开串口外设的时钟
DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
// 将USART Tx的GPIO配置为推挽复用模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
// 将USART Rx的GPIO配置为浮空输入模式
GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
// 配置串口的工作参数
// 配置波特率
USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
// 配置 针数据字长
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 配置停止位
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(DEBUG_USARTx, &USART_InitStructure);
// 串口中断优先级配置
NVIC_Configuration();
// 使能串口接收中断
USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);
USART_ITConfig ( DEBUG_USARTx, USART_IT_IDLE, ENABLE ); //使能串口总线空闲中断
// 使能串口
USART_Cmd(DEBUG_USARTx, ENABLE);
}
/***************** 发送一个字节 **********************/
void Usart_SendByte( USART_TypeDef * pUSARTx, uint8_t ch)
{
/* 发送一个字节数据到USART */
USART_SendData(pUSARTx,ch);
/* 等待发送数据寄存器为空 */
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
/****************** 发送8位的数组 ************************/
void Usart_SendArray( USART_TypeDef * pUSARTx, uint8_t *array, uint16_t num)
{
uint8_t i;
for(i=0; i<num; i++)
{
/* 发送一个字节数据到USART */
Usart_SendByte(pUSARTx,array[i]);
}
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET);
}
/***************** 发送字符串 **********************/
void Usart_SendString( USART_TypeDef * pUSARTx, char *str)
{
unsigned int k=0;
do
{
Usart_SendByte( pUSARTx, *(str + k) );
k++;
} while(*(str + k)!='\0');
/* 等待发送完成 */
while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
{}
}
/***************** 发送一个16位数 **********************/
void Usart_SendHalfWord( USART_TypeDef * pUSARTx, uint16_t ch)
{
uint8_t temp_h, temp_l;
/* 取出高八位 */
temp_h = (ch&0XFF00)>>8;
/* 取出低八位 */
temp_l = ch&0XFF;
/* 发送高八位 */
USART_SendData(pUSARTx,temp_h);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
/* 发送低八位 */
USART_SendData(pUSARTx,temp_l);
while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET);
}
///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到串口 */
USART_SendData(DEBUG_USARTx, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
return (ch);
}
///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
/* 等待串口输入数据 */
while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(DEBUG_USARTx);
}
rx_data_queue.h
#ifndef __ESP_DATA_QUEUE_H_
#define __ESP_DATA_QUEUE_H_
#include "stm32f10x.h"
#include <string.h>
#include <stdio.h>
//缓冲队列的个数需要为2的幂
#define QUEUE_NODE_NUM (2) //缓冲队列的大小(有多少个缓冲区)
#define QUEUE_NODE_DATA_LEN (2*1024 ) //单个接收缓冲区大小
// 队列的主体数据类型接口
#define QUEUE_DATA_TYPE ESP_USART_FRAME
// 队列的调试输出接口
#define DATA_QUEUE_LOG QUEUE_DEBUG
#define DATA_QUEUE_LOG_ARRAY QUEUE_DEBUG_ARRAY
// 数据主体
typedef struct
{
char *head; // 缓冲区头指针
uint16_t len; // 接收到的数据长度
}ESP_USART_FRAME;
// 队列结构
typedef struct {
int size; /* 缓冲区大小 */
int read; /* 读指针 */
int write; /* 写指针 */
int read_using; /* 正在读取的缓冲区指针 */
int write_using; /* 正在写入的缓冲区指针 */
QUEUE_DATA_TYPE *elems[QUEUE_NODE_NUM]; /* 缓冲区地址 */
} QueueBuffer;
extern QueueBuffer rx_queue;
/* 信息输出 */
#define QUEUE_DEBUG_ON 1
#define QUEUE_DEBUG_ARRAY_ON 1
#define QUEUE_INFO(fmt,arg...) printf("<<-QUEUE-INFO->> "fmt"\n",##arg)
#define QUEUE_ERROR(fmt,arg...) printf("<<-QUEUE-ERROR->> "fmt"\n",##arg)
#define QUEUE_DEBUG(fmt,arg...) do{\
if(QUEUE_DEBUG_ON)\
printf("<<-QUEUE-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
}while(0)
#define QUEUE_DEBUG_ARRAY(array, num) do{\
int32_t i;\
uint8_t* a = array;\
if(QUEUE_DEBUG_ARRAY_ON)\
{\
printf("\n<<-QUEUE-DEBUG-ARRAY->>\n");\
for (i = 0; i < (num); i++)\
{\
printf("%02x ", (a)[i]);\
if ((i + 1 ) %10 == 0)\
{\
printf("\n");\
}\
}\
printf("\n");\
}\
}while(0)
//输出队列的状态信息
#define cbPrint(cb) DATA_QUEUE_LOG("size=0x%x, read=%d, write=%d\n", cb.size, cb.read, cb.write);\
DATA_QUEUE_LOG("size=0x%x, read_using=%d, write_using=%d\n", cb.size, cb.read_using, cb.write_using);
QUEUE_DATA_TYPE* cbWrite(QueueBuffer *cb);
QUEUE_DATA_TYPE* cbRead(QueueBuffer *cb);
void cbReadFinish(QueueBuffer *cb);
void cbWriteFinish(QueueBuffer *cb);
//void cbPrint(QueueBuffer *cb);
QUEUE_DATA_TYPE* cbWriteUsing(QueueBuffer *cb) ;
int cbIsFull(QueueBuffer *cb) ;
int cbIsEmpty(QueueBuffer *cb) ;
void rx_queue_init(void);
void pull_data_from_queue(void);
void push_data_to_queue(char *src_dat,uint16_t src_len);
#endif
rx_data_queue.c
/**
******************************************************************************
* @file rx_data_queue.c
* @author fire
* @version V1.0
* @date 2015-01-xx
* @brief 环形缓冲区,适用于接收外部数据时用作缓冲
******************************************************************************
* @attention
*
* 实验平台:秉火 IOT STM32 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :https://fire-stm32.taobao.com
*
******************************************************************************
*/
#include "./uart/rx_data_queue.h"
//实例化节点数据类型
QUEUE_DATA_TYPE node_data[QUEUE_NODE_NUM];
//实例化队列类型
QueueBuffer rx_queue;
//队列缓冲区的内存池
__align(4) char node_buff[QUEUE_NODE_NUM][QUEUE_NODE_DATA_LEN] ;
/*环形缓冲队列*/
/**
* @brief 初始化缓冲队列
* @param cb:缓冲队列结构体
* @param size: 缓冲队列的元素个数
* @note 初始化时还需要给cb->elems指针赋值
*/
void cbInit(QueueBuffer *cb, int size)
{
cb->size = size; /* maximum number of elements */
cb->read = 0; /* index of oldest element */
cb->write = 0; /* index at which to write new element */
// cb->elems = (uint8_t *)calloc(cb->size, sizeof(uint8_t)); //elems 要额外初始化
}
//(此函数改成了宏,在头文件)
/**
* @brief 输出缓冲队列当前的状态信息
* @param cb:缓冲队列结构体
*/
//void cbPrint(QueueBuffer *cb)
//{
// DATA_QUEUE_LOG("size=0x%x, read=%d, write=%d\n", cb->size, cb->read, cb->write);
// DATA_QUEUE_LOG("size=0x%x, read_using=%d, write_using=%d\n", cb->size, cb->read_using, cb->write_using);
//}
/**
* @brief 判断缓冲队列是(1)否(0)已满
* @param cb:缓冲队列结构体
*/
int cbIsFull(QueueBuffer *cb)
{
return cb->write == (cb->read ^ cb->size); /* This inverts the most significant bit of read before comparison */
}
/**
* @brief 判断缓冲队列是(1)否(0)全空
* @param cb:缓冲队列结构体
*/
int cbIsEmpty(QueueBuffer *cb)
{
return cb->write == cb->read;
}
/**
* @brief 对缓冲队列的指针加1
* @param cb:缓冲队列结构体
* @param p:要加1的指针
* @return 返回加1的结果
*/
int cbIncr(QueueBuffer *cb, int p)
{
return (p + 1)&(2*cb->size-1); /* read and write pointers incrementation is done modulo 2*size */
}
/**
* @brief 获取可写入的缓冲区指针
* @param cb:缓冲队列结构体
* @return 可进行写入的缓冲区指针
* @note 得到指针后可进入写入操作,但写指针不会立即加1,
写完数据时,应调用cbWriteFinish对写指针加1
*/
QUEUE_DATA_TYPE* cbWrite(QueueBuffer *cb)
{
if (cbIsFull(cb)) /* full, overwrite moves read pointer */
{
return NULL;
}
else
{
//当wriet和write_using相等时,表示上一个缓冲区已写入完毕,需要对写指针加1
if(cb->write == cb->write_using)
{
cb->write_using = cbIncr(cb, cb->write); //未满,则增加1
}
}
return cb->elems[cb->write_using&(cb->size-1)];
}
/**
* @brief 数据写入完毕,更新写指针到缓冲结构体
* @param cb:缓冲队列结构体
*/
void cbWriteFinish(QueueBuffer *cb)
{
cb->write = cb->write_using;
}
/**
* @brief 获取可读取的缓冲区指针
* @param cb:缓冲队列结构体
* @return 可进行读取的缓冲区指针
* @note 得到指针后可进入读取操作,但读指针不会立即加1,
读取完数据时,应调用cbReadFinish对读指针加1
*/
QUEUE_DATA_TYPE* cbRead(QueueBuffer *cb)
{
if(cbIsEmpty(cb))
return NULL;
//当read和read_using相等时,表示上一个缓冲区已读取完毕(即已调用cbReadFinish),
//需要对写指针加1
if(cb->read == cb->read_using)
cb->read_using = cbIncr(cb, cb->read);
return cb->elems[cb->read_using&(cb->size-1)];
}
/**
* @brief 数据读取完毕,更新读指针到缓冲结构体
* @param cb:缓冲队列结构体
*/
void cbReadFinish(QueueBuffer *cb)
{
//重置当前读完的数据节点的长度
cb->elems[cb->read_using&(cb->size-1)]->len = 0;
cb->read = cb->read_using;
}
//队列的指针指向的缓冲区全部销毁
void camera_queue_free(void)
{
uint32_t i = 0;
for(i = 0; i < QUEUE_NODE_NUM; i ++)
{
if(node_data[i].head != NULL)
{
//若是动态申请的空间才要free
// free(node_data[i].head);
node_data[i].head = NULL;
}
}
return;
}
/**
* @brief 缓冲队列初始化,分配内存,使用缓冲队列时,
* @param 无
* @retval 无
*/
void rx_queue_init(void)
{
uint32_t i = 0;
memset(node_data, 0, sizeof(node_data));
/*初始化缓冲队列*/
cbInit(&rx_queue,QUEUE_NODE_NUM);
for(i = 0; i < QUEUE_NODE_NUM; i ++)
{
node_data[i].head = node_buff[i];
/*初始化队列缓冲指针,指向实际的内存*/
rx_queue.elems[i] = &node_data[i];
DATA_QUEUE_LOG("node_data[i].head=0x%x,\r\nrx_queue.elems[i] =0x%x", (uint32_t)node_data[i].head,(uint32_t)rx_queue.elems[i]->head);
memset(node_data[i].head, 0, QUEUE_NODE_DATA_LEN);
}
cbPrint(rx_queue);
}
/**
* @brief 往队列中写入数据的样例
*/
void push_data_to_queue(char *src_dat,uint16_t src_len)
{
QUEUE_DATA_TYPE *data_p;
uint8_t i;
for(i=0;i<src_len;i++)
{
/*获取写缓冲区指针,准备写入新数据*/
data_p = cbWrite(&rx_queue);
if (data_p != NULL) //若缓冲队列未满,开始传输
{
//往缓冲区写入数据,如使用串口接收、dma写入等方式
*(data_p->head + i) = src_dat[i];
data_p->len++;
printf("\r\ndata_p->len =%d",data_p->len);
}else return;
cbPrint(rx_queue);
}
/*写入缓冲区完毕*/
cbWriteFinish(&rx_queue);
cbPrint(rx_queue);
}
/**
* @brief 从队列中取数据的样例
*/
void pull_data_from_queue(void)
{
QUEUE_DATA_TYPE *rx_data;
/*从缓冲区读取数据,进行处理,*/
rx_data = cbRead(&rx_queue);
if(rx_data != NULL)//缓冲队列非空
{
//加上字符串结束符,方便直接输出字符串
*(rx_data->head+rx_data->len) = '\0';
QUEUE_DEBUG("接收到的数据:%s",rx_data->head);
QUEUE_DEBUG_ARRAY((uint8_t*)rx_data->head,rx_data->len);
//使用完数据必须调用cbReadFinish更新读指针
cbReadFinish(&rx_queue);
}
}
stm32f10x_it.c中添加函数:
// 串口中断服务函数
// 把接收到的数据写入缓冲区,在main函数中轮询缓冲区输出数据
void DEBUG_USART_IRQHandler(void)
{
uint8_t ucCh;
QUEUE_DATA_TYPE *data_p;
if(USART_GetITStatus(DEBUG_USARTx,USART_IT_RXNE)!=RESET)
{
ucCh = USART_ReceiveData( DEBUG_USARTx );
/*获取写缓冲区指针,准备写入新数据*/
data_p = cbWrite(&rx_queue);
if (data_p != NULL) //若缓冲队列未满,开始传输
{
//往缓冲区写入数据,如使用串口接收、dma写入等方式
*(data_p->head + data_p->len) = ucCh;
if( ++data_p->len >= QUEUE_NODE_DATA_LEN)
{
cbWriteFinish(&rx_queue);
}
}else return;
}
if ( USART_GetITStatus( DEBUG_USARTx, USART_IT_IDLE ) == SET ) //数据帧接收完毕
{
/*写入缓冲区完毕*/
cbWriteFinish(&rx_queue);
ucCh = USART_ReceiveData( DEBUG_USARTx ); //由软件序列清除中断标志位(先读USART_SR,然后读USART_DR)
}
}
bsp_led.h
/* 和LED功能模块相关的程序 */
#ifndef __BSP_LED_H__
#define __BSP_LED_H__
#include "stm32f10x.h"
/*宏定义*/
#define GPIO_CLK_D4 RCC_APB2Periph_GPIOC // 时钟
#define GPIO_PORT_D4 GPIOC // C端口
#define GPIO_PIN_D4 GPIO_Pin_2 // PC2引脚
#define GPIO_CLK_D5 RCC_APB2Periph_GPIOC // 时钟
#define GPIO_PORT_D5 GPIOC // C端口
#define GPIO_PIN_D5 GPIO_Pin_3 // PC2引脚
/*参数宏定义*/
/*
digitalTOGGLE(p,i)是参数宏定义,p表示LED的端口号,ODR是数据输出寄存器,
查stm32f10x的官方中文手册的第8.2章的ODR寄存器,要点亮LED,根据原理图,要输出低电平0,
C语言中,^表示异或,即a^b表示a和b不同时输出为1,相同时输出为0,比如0^1=1,1^1=0,0^0=0,
这里为什么操作ODR,p是什么?查看stm32f10x.h文件,搜索GPIO_TypeDef就会明白,
i是LED的引脚对应的位电平,经过digitalTOGGLE(p,i) {p->ODR ^= i;}之后,
第一次p为0,i一直为1,第一次异或结果输出1,第二次输出0,第三次输出1,这样间断输出010101,灯不断亮灭
*/
// LED灯的状态翻转
//#define digitalTOGGLE(p,i) {p->ODR ^= i;}
// 输出高电平(让LED端口置1,BSRR寄存器用于位置1)
#define digitalHi(p,i) {p->BSRR = i;}
// 输出低电平(让LED端口置0,BRR寄存器用于位清除)
#define digitalLo(p,i) {p->BRR = i;}
// LED状态翻转
//#define LED1_TOGGLE digitalTOGGLE(GPIO_PORT_D4,GPIO_PIN_D4)
//#define LED2_TOGGLE digitalTOGGLE(GPIO_PORT_D5,GPIO_PIN_D5)
// D4这个LED亮
#define D4_LED_ON digitalLo(GPIO_PORT_D4,GPIO_PIN_D4)
// D4这个LED灭
#define D4_LED_OFF digitalHi(GPIO_PORT_D4,GPIO_PIN_D4)
// D5这个LED亮
#define D5_LED_ON digitalLo(GPIO_PORT_D5,GPIO_PIN_D5)
// D5这个LED灭
#define D5_LED_OFF digitalHi(GPIO_PORT_D5,GPIO_PIN_D5)
/*配置GPIO*/
void LED_GPIO_Config(void);
#endif /*__BSP_LED_H__*/
bsp_led.c
/* 和LED功能模块相关的程序头文件 */
/*绝对路径,也可在Options for target中设置头文件*/
#include "./led/bsp_led.h"
/*GPIO初始化*/
void LED_GPIO_Config(void)
{
/*外设结构体*/
GPIO_InitTypeDef GPIO_InitStruct_D4, GPIO_InitStruct_D5;
/*第一步:打开外设的时钟,看stm32f10x_rcc.c这个文件的RCC_APB2PeriphClockCmd函数介绍*/
RCC_APB2PeriphClockCmd(GPIO_CLK_D4, ENABLE);
/*第二步:配置外设的初始化结构体*/
GPIO_InitStruct_D4.GPIO_Pin = GPIO_PIN_D4; // PC2的那盏LED灯(D4)的引脚
GPIO_InitStruct_D4.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStruct_D4.GPIO_Speed = GPIO_Speed_10MHz; // 引脚速率
GPIO_InitStruct_D5.GPIO_Pin = GPIO_PIN_D5; // PC3的那盏LED灯(D5)的引脚
GPIO_InitStruct_D5.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStruct_D5.GPIO_Speed = GPIO_Speed_10MHz; // 引脚速率
/*第三步:调用外设初始化函数,把配置好的结构体成员写到寄存器里面*/
GPIO_Init(GPIO_PORT_D4, &GPIO_InitStruct_D4);
GPIO_Init(GPIO_PORT_D5, &GPIO_InitStruct_D5);
/* 默认情况下D4和D5是不亮的 */
D4_LED_OFF;
D5_LED_OFF;
}
bsp_buzzer.h
#ifndef __BSP_BUZZER_H__ #define __BSP_BUZZER_H__ #include "stm32f10x.h" // 蜂鸣器用到的引脚(PC1) #define GPIO_BUZZER_CLK RCC_APB2Periph_GPIOC #define GPIO_BUZZER_PORT GPIOC #define GPIO_BUZZER_PIN GPIO_Pin_1 /*蜂鸣器GPIO端口初始化*/ void GPIO_Buzzer_Init(void); /*蜂鸣器发声*/ void Buzzer_Lissen(void); /*关闭蜂鸣器*/ void Buzzer_Close(void); #endif /*__BSP_BUZZER_H__*/
bsp_buzzer.c
#include "./buzzer/bsp_buzzer.h"
/*延迟函数*/
static void Delay(__IO uint32_t time)
{
for(;time!=0;time--);
}
/*蜂鸣器GPIO端口初始化*/
void GPIO_Buzzer_Init(void)
{
// 结构体
GPIO_InitTypeDef GPIO_InitStruct;
// 开时钟
RCC_APB2PeriphClockCmd(GPIO_BUZZER_CLK, ENABLE);
// 实例化
GPIO_InitStruct.GPIO_Pin = GPIO_BUZZER_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
// 初始化
GPIO_Init(GPIO_BUZZER_PORT, &GPIO_InitStruct);
}
/*蜂鸣器发声*/
void Buzzer_Lissen(void)
{
uint32_t i = 10000;
// 产生PWM波,高低电平振荡发声
//while(i--)
//{
GPIO_SetBits(GPIO_BUZZER_PORT, GPIO_BUZZER_PIN);
Delay(100*i);
GPIO_ResetBits(GPIO_BUZZER_PORT, GPIO_BUZZER_PIN);
Delay(200*i);
//}
}
/*关闭蜂鸣器*/
void Buzzer_Close(void)
{
//uint32_t j = 10000;
// 产生PWM波,高低电平振荡发声
//while(j--)
//{
GPIO_ResetBits(GPIO_BUZZER_PORT, GPIO_BUZZER_PIN);
//}
}
main.c
#include "stm32f10x.h"
#include "./uart/bsp_usart.h"
#include "./led/bsp_led.h"
#include "./buzzer/bsp_buzzer.h"
int main(void)
{
// 接收到的数据存放到局部变量中
uint8_t temp;
/* LED初始化 */
LED_GPIO_Config();
GPIO_Buzzer_Init();
/* USART串口通信初始化 */
USART_Config();
// 控制LED和蜂鸣器
while(1)
{
temp = USART_ReceiveData(DEBUG_USARTx);
switch(temp)
{
case '0':
D4_LED_OFF;
break;
case '1':
D4_LED_ON;
break;
case '2':
Buzzer_Lissen();
break;
case '3':
Buzzer_Close();
break;
}
}
}
Java代码:

index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>Web控制51单片机的各个功能模块之案例测试</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<script type="text/javascript">
// 开LED
function goON() {
var parameterId = document.getElementById("parameterId");
parameterId.value = "on";
document.forms[0].submit();
}
// 关LED
function goOFF() {
var parameterId = document.getElementById("parameterId");
parameterId.value = "off";
document.forms[0].submit();
}
// 开蜂鸣器
function buzzer_goON() {
var parameterId = document.getElementById("parameterId");
parameterId.value = "buzzer_on";
document.forms[0].submit();
}
// 关蜂鸣器
function buzzer_goOFF() {
var parameterId = document.getElementById("parameterId");
parameterId.value = "buzzer_off";
document.forms[0].submit();
}
</script>
</head>
<body>
<h2>========= Java和STM32串口通信实验 =========</h2>
说明:按下“开灯”按钮打开LED灯,按下“关灯”按钮关闭LED灯
<br><br>
<form name="myForm" action="operator" method="post" style="margin-left: 200px;">
<input type="hidden" name="parameter" id="parameterId"/>
<table cellpadding="7" cellspacing="10">
<tr>
<td>
<input type="hidden" name="on" value="1" readonly="readonly"/>
<input type="button" value="开灯" onclick="goON();" style="font-size: 20px;"/>
</td>
<td>
<input type="hidden" name="off" value="0" readonly="readonly"/>
<input type="button" value="关灯" onclick="goOFF();" style="font-size: 20px;"/>
</td>
</tr>
<tr>
<td>
<input type="hidden" name="buzzer_on" value="2" readonly="readonly"/>
<input type="button" value="开蜂鸣器" onclick="buzzer_goON();" style="font-size: 20px;"/>
</td>
<td>
<input type="hidden" name="buzzer_off" value="3" readonly="readonly"/>
<input type="button" value="关蜂鸣器" onclick="buzzer_goOFF();" style="font-size: 20px;"/>
</td>
</tr>
</table>
</form>
</body>
</html>
web.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> <web-app> <servlet> <servlet-name>operator</servlet-name> <servlet-class>com.lvshitech.java51.server.MyServer</servlet-class> </servlet> <servlet-mapping> <servlet-name>operator</servlet-name> <url-pattern>/operator</url-pattern> </servlet-mapping> </web-app>
MyServer.java
package com.lvshitech.java51.server;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lvshitech.java51.tool.Tools;
@SuppressWarnings("serial")
public class MyServer extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// 获取参数
String parameter = req.getParameter("parameter");
String on = req.getParameter("on");
String off = req.getParameter("off");
String buzzer_on = req.getParameter("buzzer_on");
String buzzer_off = req.getParameter("buzzer_off");
try {
if(null==parameter || "".equals(parameter)) {
System.out.println("接收到的参数为空!");
} else {
if("on".equals(parameter)) {
Tools.action(on);
}
if("off".equals(parameter)) {
Tools.action(off);
}
if("buzzer_on".equals(parameter)) {
Tools.action(buzzer_on);
}
if("buzzer_off".equals(parameter)){
Tools.action(buzzer_off);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
Tools.closePort();
}
req.getRequestDispatcher("index.jsp").forward(req, resp);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
this.doPost(req, resp);
}
}
Tools.java
package com.lvshitech.java51.tool;
import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Enumeration;
public class Tools {
public static SerialPort serialPort=null;
/*类方法 不可改变 不接受继承
* 扫描获取可用的串口
* 将可用串口添加至list并保存至list
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public static final ArrayList<String> uartPortUseAblefind() {
//获取当前所有可用串口
//由CommPortIdentifier类提供方法
Enumeration<CommPortIdentifier> portList=CommPortIdentifier.getPortIdentifiers();
ArrayList<String> portNameList=new ArrayList();
//添加并返回ArrayList
while(portList.hasMoreElements()) {
String portName=portList.nextElement().getName();
portNameList.add(portName);
}
return portNameList;
}
/*
* 串口常见设置
* 1)打开串口
* 2)设置波特率 根据单板机的需求可以设置为57600 ...
* 3)判断端口设备是否为串口设备
* 4)端口是否占用
* 5)对以上条件进行check以后返回一个串口设置对象new UARTParameterSetup()
* 6)return:返回一个SerialPort一个实例对象,若判定该com口是串口则进行参数配置
* 若不是则返回SerialPort对象为null
*/
public static final SerialPort portParameterOpen(String portName,int baudrate) {
try { //通过端口名识别串口
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier(portName);
//打开端口并设置端口名字 serialPort和超时时间 2000ms
CommPort commPort=portIdentifier.open(portName,1000);
//进一步判断comm端口是否是串口 instanceof
if(commPort instanceof SerialPort) {
System.out.println("该COM端口是串口!串口名称是:" + portName);
//进一步强制类型转换
serialPort=(SerialPort)commPort;
//设置baudrate 此处需要注意:波特率只能允许是int型 对于57600足够
//8位数据位
//1位停止位
//无奇偶校验
serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8,SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
//串口配制完成 log
System.out.println("串口参数设置已完成,波特率为"+baudrate+",数据位8bits,停止位1位,无奇偶校验");
} else { //不是串口
System.out.println("该com端口不是串口,请检查设备!");
//将com端口设置为null 默认是null不需要操作
}
} catch (NoSuchPortException e) {
e.printStackTrace();
} catch (PortInUseException e) {
e.printStackTrace();
} catch (UnsupportedCommOperationException e) {
e.printStackTrace();
}
return serialPort;
}
/*
* 串口数据发送以及数据传输作为一个类
* 该类做主要实现对数据包的传输至下单板机
*/
/*
* 上位机往单板机通过串口发送数据
* 串口对象 seriesPort
* 数据帧:dataPackage
* 发送的标志:数据未发送成功抛出一个异常
*/
public static void uartSendDatatoSerialPort(SerialPort serialPort,byte[] dataPackage) {
OutputStream out=null;
try {
out=serialPort.getOutputStream();
out.write(dataPackage);
out.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
//关闭输出流
if(out!=null) {
try {
out.close();
out=null;
//System.out.println("数据已发送完毕!");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
* 上位机接收数据
* 串口对象seriesPort
* 接收数据buffer
* 返回一个byte数组
*/
public static byte[] uartReceiveDatafromSingleChipMachine(SerialPort serialPort) {
byte[] receiveDataPackage=null;
InputStream in=null;
try {
in=serialPort.getInputStream();
// 获取data buffer数据长度
int bufferLength=in.available();
while(bufferLength!=0) {
receiveDataPackage=new byte[bufferLength];
in.read(receiveDataPackage);
bufferLength=in.available();
}
} catch (IOException e) {
e.printStackTrace();
}
return receiveDataPackage;
}
public static void action(String parameter) throws Exception {
// 打开串口
SerialPort serialPort = portParameterOpen("COM3", 115200);
// 要发送的数据
String dataSend = parameter;
int i=1;
//while(true) {
// 发送数据到单片机
byte []datByte = dataSend.getBytes();
uartSendDatatoSerialPort(serialPort, datByte);
System.out.println("-------------------------------------------------------");
System.out.println((i++) + ". 发送到串口的数据:" + dataSend);
// 休眠500ms,等待单片机反应
//Thread.sleep(500);
// 从单片机接收到的数据
/*
byte[] dat = uartReceiveDatafromSingleChipMachine(serialPort);
if(dat != null && dat.length > 0) {
String dataReceive = new String(dat, "GB2312");
System.out.println((i++) + ". 从串口接收的数据:" + dataReceive);
} else {
System.out.println("接收到的数据为空!");
}
*/
//}
}
/**
* 关闭串口
* @param serialport 待关闭的串口对象
*/
public static void closePort() {
if (serialPort != null) {
serialPort.close();
serialPort = null;
}
}
}

浙公网安备 33010602011771号