当前位置:首页 > 嵌入式 > 嵌入式硬件
[导读]最近在淘宝逛的时候发现了一款单片机,STM8。相比之前一直使用的也是8位的AVR相比,感觉STM8更为强大,芯片特点如下:本文引用地址:http://www.eepw.com.cn/article/20170

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

本文引用地址:http://www.eepw.com.cn/article/201709/364742.htm

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

程序存储器:8K字节Flash;RAM: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计数器溢出中断

里面添加初始化ADC0832和ADC0832数据读取并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计数器溢出中断[!--empirenews.page--]

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

程序包括初始化STM8的GPIO,初始化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");[!--empirenews.page--]

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

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

蓝牙使用射频无线技术在2.4 GHz频段进行通信。它采用了频分复用(Frequency Hopping Spread Spectrum,FHSS)技术,通过在不同的频率上快速切换传输数据,以减少干扰和提高可靠性。

关键字: 蓝牙通信 射频 无线技术

蓝牙通信是一种基于短距离无线技术的通信方式,可以在各种设备之间进行数据传输和语音通信。蓝牙技术采用分散式网络结构和快跳频技术,支持点对点及点对多点通信,工作在全球通用的2.4GHz ISM频段,其数据速率为1Mbps,采...

关键字: 蓝牙通信 蓝牙模块

蓝牙是一种支持设备短距离通信(一般10m内)的无线电技术,能在包括移动电话、PDA、无线耳机、笔记本电脑、相关外设等众多设备之间进行无线信息交换。利用“蓝牙”技术,能够有效地简化移动通信终端设备之间的通信,也能够成功地简...

关键字: 蓝牙通信 智能手机

上海2023年9月20日 /美通社/ -- 2023年9月19日-23日,第二十三届中国国际工业博览会(以下简称“工博会”)在国家会展中心(上海)举行,来自全球30个国家和地区的2800家展商,覆盖从基础材料、基础零部件...

关键字: 富士 存储技术 IBM 数据流

上海2022年12月16日 /美通社/ -- 近期,涅槃汽车发表了一篇文章,对智能座舱数据存储技术进行解析,内容如下: 1、 智能座舱的存储越来越重要,容量越大越大。 我们都知道,中国新能源汽车逐步在迈向正...

关键字: 数据存储 汽车 存储技术 BSP

我们前面主要去学习了蓝牙开发所具备的基础知识、常用的仿真手法,那么如何去分析我们抓到的蓝牙通信包呢?不去学习蓝牙通信协议,只能把抓到的Log信息,交给能看懂的人,你也最终只能当一个测试工程师了。

关键字: 基础知识 仿真手法 蓝牙通信

北京2022年10月11日 /美通社/ -- 在1992年出版的《雪崩》一书中,作者尼尔·史蒂芬森第一次提出Metaverse(元宇宙)这一概念;斗转星移,三十年之后,随着Roblox上市、Facebook...

关键字: 区块链 存储技术 带宽 分布式

(全球TMT2022年8月4日讯)近日,Gartner公布2022年存储和数据保护技术成熟度曲线(Hype Cycle for Storage and Data Protection Technologies, 202...

关键字: 分布式 存储技术 GARTNER 软件定义

北京2022年4月28日 /美通社/ -- 数据是元宇宙的核心要素,面对元宇宙时代的海量数据爆发,如何实现安全、可靠、高效存储?日前,浪潮信息参与第五期开放计算技术沙龙“元宇宙存储研究与实践”,与来自中国科学技术大学、郑...

关键字: 区块链 云存储 数据中心 存储技术

北京, 2022年4月2日 /美通社/ -- 新一代信息技术正加速数字经济时代的到来,数据作为数字经济时代的信息支撑,数据成为继土地、劳动力、资本、技术之后的第五大生产要素,正在成为驱动经济社会发展的重要力量。 数据也...

关键字: 存储技术 AI
关闭
关闭