基于STM8的ADC0832采集及蓝牙通信系统

2023-11-16

为了方便大家学习,工程已经打包上传,http://download.csdn.net/detail/devintt/8029389


最近在淘宝逛的时候发现了一款单片机,STM8。相比之前一直使用的也是8位的AVR相比,感觉STM8更为强大,芯片特点如下:


内核:具有3级流水线的哈佛结构、扩展指令集

程序存储器8K字节FlashRAM:1K字节

数据存储器640 字节真正的数据EEPROM;可达30万次擦写

更重要的一点就是STM8系列若使用库编程的话,可以方便的不同芯片的程序移植。甚至可以方便的移植到STM32上面,大大减轻了更新硬件的重写程序的工作量。

 

ADC0832 为8位分辨率A/D转换芯片,其最高分辨可达256级,可以适应一般的模拟量转换要求。其内部电源输入与参考电压的复用,使得芯片的模拟电压输入在0~5V之间。芯片转换时间仅为32μS,据有双数据输出可作为数据校验,以减少数据误差,转换速度快且稳定性能强。独立的芯片使能输入,使多器件挂接和处理器控制变的更加方便。通过DI 数据输入端,可以轻易的实现通道功能的选择。(简述和图片均来之百度百科)


本文适合STM8控制ADC0832,程序是使用库编程,编译工具IAR。其实STM8也自带ADC转换模块了......

     本程序还包括蓝牙串口通信,方便将得到数据从串口输出,我是编写了安卓上位机的app,方便在安卓上面显示图像。

程序还是用了定时器TIM4,确保每次采样的间隔大致相等,对之后的数据处理提供了基础。

 

先介绍核心mian.c文件,主要功能是初始化串口UART1,定时器TIMER4,还有一个发送16进制的函数。其中发送完数据再发送一个字符’U’作为一个数据的结束(你也可以自己定义)。这里说说为什么要选用16进制,而不是10进制,STM8速度有限,为了减少单指令操作,程序用了移位操作,这样可得到16进制每位数值,在发送到安卓上位机,上位机运算速度快,再转化成10进制,这样可以资源合理分配。

main.c程序:

#include "stm8s.h"
#include "stm8s_it.h"

uint8_t HexTable[]={'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
uint8_t i=0;

//串口UART1初始化
void Init_UART(void)
{
  //默认初始化
  UART1_DeInit();       
  //设置波特率9600 8位数据 1位停止位 无校验  外部时钟不可用 模式接收发送
  UART1_Init((u32)9600, UART1_WORDLENGTH_8D, UART1_STOPBITS_1, UART1_PARITY_NO, UART1_SYNCMODE_CLOCK_DISABLE, UART1_MODE_TXRX_ENABLE);
  //设置接收寄存器溢出中断
  UART1_ITConfig(UART1_IT_RXNE_OR, ENABLE);
}
//定时器TIM4初始化
void Init_Timer4(void)
{
  //1ms中断一次
  TIM4_TimeBaseInit(TIM4_PRESCALER_128, 124);
  /* Clear TIM4 update flag */
  TIM4_ClearFlag(TIM4_FLAG_UPDATE);
  /* Enable update interrupt */
  TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);
  TIM4_Cmd(ENABLE);
}
//发送字节
void Send(uint8_t dat)
{
  //检查并等待发送寄存器是否为空
  while(( UART1_GetFlagStatus(UART1_FLAG_TXE)==RESET));
  //发送字节
  UART1_SendData8(dat);
}
//发送16位16进制
void UART1_mysend16hex(u16 dat)
{
    Send(HexTable[(dat>>12)&0x0f]);
    Send(HexTable[(dat>>8)&0x0f]);
    Send(HexTable[(dat>>4)&0x0f]);
    Send(HexTable[(dat)&0x0f]);
}
//发送8位16进制
void UART1_mysend8hex(uint8_t dat)
{
    Send(HexTable[(dat>>4)&0x0f]);
    Send(HexTable[(dat)&0x0f]);
    Send('U');
}
void main()
{
  //初始化
  Init_UART();
  Init_Timer4();
  //中断开启
  enableInterrupts(); 
  while(1)
  {
  }
}

//这个必须加上 不然会报错 估计是库的要求

#ifdef USE_FULL_ASSERT
void assert_failed(u8* file, u32 line)
{ 
  while (1)
  {
  }
}
#endif


接下来说说中断函数表stm8s_it.c

其中只要选用两个中断函数就可以了:

INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18) 接收寄存器溢出中断

里面添加安卓上位机发送过来的数据的处理程序,我这里写的是ADC0832通道选择的判断。

INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23) 定时器4计数器溢出中断

里面添加初始化ADC0832ADC0832数据读取并UART1发送到安卓上位机。

stm8s_it.c程序:

#include "stm8s_it.h"
#include "ADC0832.h"
extern uint8_t i;
uint8_t channel=1 ;

//接收寄存器溢出中断
INTERRUPT_HANDLER(UART1_RX_IRQHandler, 18)
 {
    /* In order to detect unexpected events during development,
       it is recommended to set a breakpoint on the following instruction.
*/
//下面是我做的安卓上位机发送过来的数据判断,这里可以改成自己想要的程序
  uint8_t tempData;
  tempData = UART1_ReceiveData8();
  if(tempData=='A')
  {
    channel = 0;
  } 
  if(tempData=='Z')
  {
    channel = 1;
  }
//清除UART1中断标识符
    UART1_ClearITPendingBit(UART1_IT_RXNE);
 }

//定时器4计数器溢出中断
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23)
 {
  /* In order to detect unexpected events during development,
     it is recommended to set a breakpoint on the following instruction.
  */
   //1*10m执行一次
   i++;
   if(i==10)
   {
    //进行ADC数模转换
//初始化ADC芯片,写入通道
    AD_init(channel);
u8 u8_adc1_value;
//进行数据读出
u8_adc1_value = AD_read();
//发送8位数据
UART1_mysend8hex(u8_adc1_value);
//清除UART1中断标识符
    UART1_ClearITPendingBit(UART1_IT_RXNE);
    i=0;
   }
   TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
 }

这里说说ADC0832的操作函数:ADC0832.c

程序包括初始化STM8GPIO,初始化ADC0832和读取ADC0832数据

主要是DODI端口复用的问题,由于STM8端口作为输入输出,需要重新初始化GPIO,所以比一般51单片机的程序要复杂一点。最后读取数据先是从高位读出,再低位读出,进行校验,相同数值再输出。

附上时序图


 

ADC0832.c程序:

/**********************************************
程序名称:ADC0832子程序
作    者:devinzhang91
时    间:2014.10.04
**********************************************/
#ifndef ADC0832_H
#define ADC0832_H
#include "stm8s.h"

//端口设置
#define CLK_GPIO_PORT  (GPIOC)
#define CLK_GPIO_PINS  (GPIO_PIN_3)
#define DI_GPIO_PORT  (GPIOC)
#define DI_GPIO_PINS  (GPIO_PIN_4)
#define DO_GPIO_PORT  (GPIOC)
#define DO_GPIO_PINS  (GPIO_PIN_4)
#define CS_GPIO_PORT  (GPIOC)
#define CS_GPIO_PINS  (GPIO_PIN_1)

/********************************************************
函数名称:void ioInit(void)
函数作用:初始化GPIO
参数说明:null
********************************************************/
void ioInit(void)
{
  //全为输出模式
  GPIO_Init(CLK_GPIO_PORT, CLK_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  GPIO_Init(DI_GPIO_PORT, DI_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  GPIO_Init(DO_GPIO_PORT, DO_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  GPIO_Init(CS_GPIO_PORT, CS_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
}

/********************************************************
函数名称:void ioChange()
函数作用:初始化GPIO
参数说明:i=0,表示输出,i=1,表示输入
********************************************************/
void ioChange(uchar i)
{
  if( i == 0)
    GPIO_Init(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS, GPIO_MODE_OUT_PP_LOW_FAST);
  if( i == 1)
    GPIO_Init(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS, GPIO_MODE_IN_PU_NO_IT);
}

/********************************************************
函数名称:void AD_init(uchar i)
函数作用:初始化ADC0832
参数说明:i=0,表示通道0,i=1,表示通道1
********************************************************/
void AD_init(uchar i) 
{
    ioInit();   //初始化io
    ioChange(0);  //作为输出
    GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);    //形成下降沿
    asm("nop");
    asm("nop");
    GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);       /*在第1 个时钟脉冲的下沉之前DI端必须是高电平,表示启始信号*/
    asm("nop");
    asm("nop");
    GPIO_WriteLow(CS_GPIO_PORT, (GPIO_Pin_TypeDef)CS_GPIO_PINS);  //使能ADC0832
    asm("nop");
    asm("nop");
    GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
    asm("nop");
    asm("nop");
    GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);    //形成下降沿1 
    asm("nop");
    asm("nop");         /*在第2、3个脉冲下沉之前DI端应输入2位数据用于选择通道功能*/
    if( i==0 )
      GPIO_WriteLow(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
    if( i==1 )
      GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
    asm("nop");
    asm("nop");
    GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
    asm("nop");
    asm("nop");
    GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);    //形成下降沿2 
    asm("nop");
    asm("nop");
    if( i==0 )
      GPIO_WriteLow(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
    if( i==1 )
      GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
    GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
    asm("nop");
    asm("nop");
    GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);    //形成下降沿3 
    asm("nop");
    asm("nop");
}
/********************************************************
函数名称:uchar AD_read()
函数作用:读取ADC0832转换的数据
参数说明:无
函数返回:返回8位的数据
********************************************************/
u8 AD_read()
{
    u8 temp1 = 0;
    u8 temp2 = 0;
    uchar i = 0;
    GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
    asm("nop");
    asm("nop");
     ioChange(1); //作为输入
    for(i = 0; i < 8; i++)
    {
        GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
        asm("nop");
        asm("nop");
        GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);   //形成下降沿
        asm("nop");
        asm("nop");
        temp1 = temp1 << 1;
        if(GPIO_ReadInputPin(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS) !=0)
          temp1 |= 0x01;
        else temp1 |= 0x00;
    }
    
    for(i = 0; i < 8; i++)
   {
       temp2 = temp2>>1;
       if(GPIO_ReadInputPin(DI_GPIO_PORT, (GPIO_Pin_TypeDef)DI_GPIO_PINS) !=0)
            temp2 = temp2|0x80;
       GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
       asm("nop");
       asm("nop");
       GPIO_WriteLow(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);   //形成下降沿 
       asm("nop");
       asm("nop");
    }
    GPIO_WriteHigh(CLK_GPIO_PORT, (GPIO_Pin_TypeDef)CLK_GPIO_PINS);
    asm("nop");
    asm("nop");
    GPIO_WriteHigh(DO_GPIO_PORT, (GPIO_Pin_TypeDef)DO_GPIO_PINS);
    asm("nop");
    asm("nop");
    GPIO_WriteHigh(CS_GPIO_PORT, (GPIO_Pin_TypeDef)CS_GPIO_PINS);  //使能ADC0832
    asm("nop");
    asm("nop");
       
    if(temp1 == temp2)
      return temp1;
    else
      return 0;
}
#endif

再说说安卓上位机,一个简单蓝牙接收的apk,用于实时画图,可以显示和画出一段时间内的STM8采样的数值,从后台接收数据,发送消息至进程更新UI


为了方便大家学习,工程已经打包上传,http://download.csdn.net/detail/devintt/8029389




本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

基于STM8的ADC0832采集及蓝牙通信系统 的相关文章

  • usb设备的检测及区分(sata硬盘、优盘及移动硬盘)

    原理 1 如果有外置usb设备插入 会产生 proc scsi usb storage目录 ide硬盘上默认 没有 并且会在 proc scsi usb storage目录中产生数字文件 此文件存储了设 备的相关信息 2 sys class
  • ES5和ES6声明的“全局变量”有什么不同?

    复看红宝石书关于执行上下文与作用域部分的时候发现了以前遗漏的小知识点 let和const的顶级声明不会定义在全局上下文中 1 什么是全局上下文 根据ECMAScript实现的宿主环境不同 表示全局上下文的对象可能不一样 但在浏览器中 我们所
  • ISE在线逻辑分析仪Chipscope的使用

    前言 和 Quartus 的 SingleTapII 类似 ISE 也有自己的内置在线逻辑分析仪 Chipscope 在这里记录一下 Chipscope 的主要使用方法 以便以后回顾 本文使用 UART 串口回环模块进行验证 我们要抓取的信
  • 【Linux】设计模式-----简单工厂模式

    概念 简单工厂模式即 只需要输入实例化对象的名称 工厂类就可以实例化出来需要的类 核心 实现工厂模式的核心就是多个派生类public继承基类 同时根据用户的需求在简单工厂类里面实例化基类的对象 从而根据基类里面的虚函数来实现对派生类的函数调
  • ajax核心代码提交,emlog评论ajax提交的两种方法

    推荐使用方法二 不需要修改源代码 通过正则过滤出系统的错误消息 方法一 需要修改源代码 1 include lib function base php中 function show 404 page 函数上方添加函数 显示json信息 pa

随机推荐

  • TFTP协议下载实验

    include
  • java.lang.ClassNotFoundException: Didn‘t find class “###“ on path: DexPathList

    项目场景 例如 项目场景 使用AS开发时 项目中引用了封装的aar或者第三方aar文件 并且项目使用了AndroidX时APP闪退问题 报错信息如下 报错信息截图大概如下 问题描述 Caused by java lang ClassNotF
  • 数组和链表的区别

    数组和链表的区别以及各自的优缺点 1 数组和链表的区别 1 数组的元素个数是固定的 而链表的结点个数可按需要增减 2 数组元素的存储单元在定义时分配 链表节点的存储单元在执行时动态向系统申请 3 数组的元素顺序关系由元素在数组中的位置 即下
  • cadence 批量一次性修改title 页码标题等

    1 在Cadence中 选中dsn 菜单选择edit gt browse gt titleblock 弹出此框时 一般选择 Use instances 2 弹出的titleblock窗口中 鼠标点击第一个 滑动到最后一个 按住 shift
  • ffmpeg webm 提取_使用ffmpeg将webm转换为mp4

    当我尝试将webm文件转换为mp4时 输出非常不连贯 并且似乎ffmpeg丢弃了许多帧 我使用以下命令进行转换 ffmpeg i movie webm movie mp4 ffmpeg i movie webm vcodec libx264
  • MySql-基础查询与排序

    基础查询与排序 2 1 SELECT语句基础 从表中选取数据 SELECT语句 从表中选取数据时需要使用SELECT语句 也就是只从表中选出 SELECT 必要数据的意思 通过SELECT语句查询并选取出必要数据的过程称为匹配查询或查询 q
  • [深入研究4G/5G/6G专题-54]: L3信令控制-3-软件功能与流程的切分-CU-UP网元的信令

    目录 第1章 软件架构 第2章 5G CP NRT 非实时 2 1 功能概述 2 2 功能细化 2 3 流程 2 4
  • git:将代码从一个分支转移到另一个分支

    参考 http www ruanyifeng com blog 2020 04 git cherry pick html 总结 git cherry pick commit的hash值 会自动commit git cherry pick n
  • opencv-python 中对PPT图象进行图象文字增强(重制含原版)

    话不多说直接上代码 这是原来的代码 import cv2 import numpy as np img cv2 imread D picture dabo goal png img cv2 resize img None fx 0 5 fy
  • C# 的继承(学习心得 19)

    继承允许我们根据一个类来定义另一个类 这使得创建和维护应用程序变得更容易 利于重用代码和节省开发时间 已有的类被称为的 基类 这个新的类被称为 派生类 继承的思想实现了 属于 IS A 关系 例如 哺乳动物 属于 IS A 动物 狗 属于
  • Windows下Ceres库的配置 包含四个依赖库Eigen、gflags、glad、suitesparse-metis-for-windows的配置

    一 首先Windows下Ceres库的配置过程中Eigen gflags glad是必须的 suitesparse虽不是必须但非常影响性能故也可以说是必须的 二 整个配置过程主要参考这一博客博主猪蹄97关于ceres库的配置 侵删 故读者在
  • ubuntu安装mysql并使用datagrip远程连接

    1 安装client sudo apt get install mysql server 2 mysql8默认不开启用户root 默认用户是debian sys maint 其默认密码是存在 etc mysql debian cnf sud
  • 构造函数调用顺序及初始化列表

    设有3个类A B C 其中A派生B B派生C 即 C gt B gt A 定义一个C对象 则 进入C对象的构造函数 检查C构造函数的初始化列表 看其中是否手动调用基类B构造函数 无论是否手动 都立即调用基类B构造函数 不同的是手动调用时 可
  • 12306验证码具体坐标

    如图 整张图片的大小是 293 190 单位 像素 包括下述 锦旗二字相对大图的范围是 117 0 258 29 长 141 宽 29 第一排第一张小图片的范围是 5 41 72 108 长 67 宽 67 间距都是5px 第二排第一张小图
  • Excel VBA 打开对话框,获取文件夹路径

    Excel 打开对话框 获取文件夹路径 Window 参照 選択 Item 名 取得 Public Function GetFolderName ByVal DialogType As MsoFileDialogType As String
  • MCCMNC列表

    http blog chinaunix net uid 20484604 id 1941290 html https clients txtnation com hc en us articles 218719768 MCCMNC mobi
  • ODrive踩坑(五)ODrive驱动云台电机、低齿槽转矩电机实现高精度定位

    前几篇介绍了ODrive在Windows下的使用环境搭建 驱动3508 5008无刷电机 TLE5012B AS5047P的ABI编码器配置 AS5047P SPI绝对值编码器配置 ODrive踩坑 一 windows下使用环境的搭建 od
  • DOPI EV200开发板开箱组装

    随着网友们 连续收到开发板 我再次开贴 分享下如何组装 插上配件 主板接口再次复习下 各位成员 再次认识下 主板链接FPC软排线的方向 Sensor链接 FPC软排线的方向 其他配件链接 这里特别强调下 WiFi请插到SDIO1上 如果插到
  • python实现分页

    使用python实现分页功能 当我们有大量数据需要展示时 需要对数据进行分页展示 这时就用到了分页功能 分页使得数据更好的展示给用户 当访问页码数大于总页码数的时候 展示第一页内容 import math content name aa a
  • 基于STM8的ADC0832采集及蓝牙通信系统

    为了方便大家学习 工程已经打包上传 http download csdn net detail devintt 8029389 最近在淘宝逛的时候发现了一款单片机 STM8 相比之前一直使用的也是8位的AVR相比 感觉STM8更为强大 芯片