在stm32中要实现数据通讯,首先要设置相关的寄存器,这里不做相关的介绍,直接说代码相关的能内容及相关函数对应的用法。
直接上代码。
1.串口通讯代码
usart.h
#ifndef __USART_H
#define __USART_H
#include "stdio.h"
#include "sys.h"
#define USART_REC_LEN 200 //定义最大接收字节数 200
#define EN_USART3_RX 1 //使能(1)/禁止(0)串口1接收
extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA; //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 bound);
#endif
对应的usart.c代码
#include "sys.h"
#include "usart.h"
//加入以下代码,支持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函数
int fputc(int ch, FILE *f)
{
while((USART3->SR&0X40)==0);//循环发送,直到发送完毕
USART3->DR = (u8) ch;
return ch;
}
#endif
/*使用microLib的方法*/
/*
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (uint8_t) ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) {}
return ch;
}
int GetKey (void) {
while (!(USART1->SR & USART_FLAG_RXNE));
return ((int)(USART1->DR & 0x1FF));
}
*/
#if EN_USART3_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA=0; //接收状态标记
void uart_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3,ENABLE);//使能USART1,GPIOA时钟
//USART3_TX GPIOB.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //PB.10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.10
//USART3_RX GPIOB.11初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB.11
//Usart3 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART3_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 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
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(USART3, &USART_InitStructure); //初始化串口3
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//开启串口接受中断
USART_Cmd(USART3, ENABLE); //使能串口3
}
void USART3_IRQHandler(void) //串口3中断服务程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntEnter();
#endif
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)
{
Res = USART_ReceiveData(USART3); //读取接收到的数据
printf("get data %c \r\n",Res);
if((USART_RX_STA&0x8000)==0)//接收未完成
{
if(USART_RX_STA&0x4000)//接收到了0x0d
{
if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
else USART_RX_STA|=0x8000; //接收完成了
}
else //还没收到0X0D
{
if(Res==0x0d)USART_RX_STA|=0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
USART_RX_STA++;
if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
OSIntExit();
#endif
}
#endif
通过上述的函数,只需要在main函数设置相关的打印函数即可打印相关的内容,这里不做相关的陈述,后面主函数会进行相关的设置。
2.进行相关的adc函数配置
adc.h函数代码如下:
#ifndef __ADC_H
#define __ADC_H
#include "sys.h"
void Adc_Init(void);
u16 Get_Adc(u8 ch);
u16 Get_Adc_Average(u8 ch,u8 times);
#endif
对应的adc.c函数代码:
#include "adc.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////
//adc配置函数
//////////////////////////////////////////////////////////////////////////////////
//初始化ADC
//我们默认将开启通道0~3
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE ); //使能ADC1通道时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
//PC0 作为interwetten与威廉的赔率体系
通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOC, &GPIO_InitStructure);
ADC_DeInit(ADC1); //复位ADC1
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC_ResetCalibration(ADC1); //使能复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
}
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)
{
//设置指定ADC的规则组通道,一个序列,采样时间
ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}
u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t;t++)>
3.主函数内容
#include "delay.h"
#include "common.h"
#include "usart.h"
#include "can.h"
#include "string.h"
#define adcx adc;
int main(void)
{
int real_100_vol;
u8 Res,res,data;
u16 adcx;
u8 i=0,t=0;
u8 cnt=11;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
Adc_Init(); //adc初始化
CAN_Mode_Init(CAN_SJW_1tq,CAN_BS2_8tq,CAN_BS1_9tq,8,CAN_Mode_LoopBack);//CAN初始化环回模式,波特率500Kbps ,设置8为500k,设置4为250k
printf("APP start OK!\r\n");
while(1)
{
char canbuf_8;
int a = 165;
adc=Get_Adc_Average(ADC_Channel_10,50);
vol_led=(float)adc*(3.3/4096);
// adcx=vol_led;
// vol_led-=adcx;
// vol_led*=1000;
printf("AD值:%d\r\n 电压值:%f V",adc,vol_led); //打印ad值和电压值
H文件与C文件进行配置。
即可通过串口读取到相关的数据AD值和电压值。
审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
寄存器
+关注
关注
31文章
5336浏览量
120244 -
数据
+关注
关注
8文章
7006浏览量
88947 -
串口
+关注
关注
14文章
1551浏览量
76438
发布评论请先 登录
相关推荐
维爱普 数据通讯设备稳定性:滤波器的核心作用
在当今这个信息爆炸的时代,数据通讯设备已经成为我们日常生活中不可或缺的一部分。无论是智能手机、电脑,还是网络通信基站、数据中心,这些设备都在不断地传输、处理着海量的数据。然而,在
安信可智能无线数据通讯Ra-09-DTU
Ra-09-DTU 是由安信可科技开发的一款智能无线数据通讯DTU,采用Ra-09 LoRa 模组,利用 LoRa 无线威廉希尔官方网站
可用于超长距离扩频通信。其芯片 STM32WLE5CCU6 是通用
求助,关于ADS125H02数据通讯格式及CRC校验问题求解
of the initial data.
第1条中,将所有数据“左移扩展为40bit,最右边用1补齐”,与传统的crc计算方法不一致,传统的计算方法是在数据末尾补8个0。是手册笔误还是本就与正常的crc计算方法
发表于 12-03 06:54
EtherCAT转Modbus TCP总线协议转换网关
远创智控YC-ECT-TCP型网关实现EtherCAT网络与Modbus TCP网络之间的数据通讯,即将Modbus TCP设备转换为EtherCAT设备。
EtherCAT转Modbus TCP协议网关(JM-ECT-TCP)
JM-ECT-TCP网关实现EtherCAT网络与Modbus TCP网络之间的数据通讯,即将Modbus TCP设备转换为EtherCAT设备。
STM32F103 USB通讯出现数据丢失的原因?如何解决?
用ST32F103的USB 做数据通讯,有大量的数据通过电脑发送到设备,少量数据回传到电脑,中断优先级设为2 ,还有几个定时器的也是中断,优先级比USB通讯的高,发现在大量连续发送
发表于 04-29 07:28
浅谈光伏电站数据通讯管理机的设计与应用
浅谈光伏电站数据通讯管理机的设计与应用 张颖姣 江苏安科瑞电器制造有限公司江苏江阴214405 摘要 :设计了一种分布式光伏电站数据通讯管理机,包括硬件系统和软件系统.硬件系统基于ARM嵌入式处理器
PLC之间数据通讯,PLC与智能仪表、设备之间WIFI无线通讯
各种PLC之间双向通讯 不同品牌不同型号的PLC,实现多对多的N:N通讯;同时支持以太网、串口连接;无需编写程序,简单配置主从站点的起始地址、数据长度即可;各站点多线程方式独立运行,
发表于 01-07 11:22
虹科威廉希尔官方网站 | 保障数据传输稳定性:BabyLIN产品的CRC算法实现
CRC校验(循环冗余校验)是数据通讯中最常采用的校验方式。CAN协议中,总线通信节点也常采用CRC算法对各种总线传输的数据进行校验。
PLC通过智能网关,与OPCUA服务端通讯,实现标签数据读写
通过‘功能’->‘数据上报与平台对接’,选择‘专用协议数据通讯’,进入以下页面配置发送数据(OPCUA发送到PLC的数据)、接收数据
发表于 01-02 16:41
评论