# LAB: ADC - IR reflective sensor

**Date:** 2025-11-06

**Author/Partner:**

**Github:** repository link

**Demo Video:** Youtube link

**PDF version:**

## Introduction

Create a simple program that uses ADCs to use analog sensors. For this lab, we will use two IR reflective sensors.

The ADCs are triggered by a timer at the given sampling rate.

This lab will be extended to Project: Line Tracing Car

You must submit

* LAB Report (\*.md & \*.pdf)
* Zip source files(main\*.c, ecRCC.h, ecGPIO.h, ecSysTick.c etc...).
  * Only the source files. Do not submit project files

### Requirement

#### Hardware

* MCU
  * NUCLEO-F411RE
* Actuator/Sensor/Others:
  * IR Reflective Sensor (TCRT 5000) x2

#### Software

* Keil uVision, CMSIS, EC\_HAL library

## Problem 0: STM-Arduino

### Procedure

1. Create a new project under the directory`\repos\EC\LAB\LAB_ADC`
2. Follow the tutorial: [**ADC with photodector and sound sensor**](https://ykkim.gitbook.io/ec/ec-course/tutorial/tutorial-arduino-stm32/tutorial-arduino-stm32-part-2#adc)

{% embed url="<https://ykkim.gitbook.io/ec/ec-course/tutorial/tutorial-arduino-stm32/tutorial-arduino-stm32-part-2#pwm-pulse-width-modulation-ultra-sonic-sensor>" %}

## Problem 1: EC library

### (Option 1) Use the provided library

Download Library Header Files (solution)

* [ecADC2.h, ecADC2.c](https://github.com/ykkimhgu/EC-student/tree/main/include/lib-student)

```cpp
/////////////////////////////////////////////////////
// ADC default setting
/////////////////////////////////////////////////////

// ADC init
// Default:  one-channel mode, continuous conversion
// Default: HW trigger - TIM3 counter, 1msec
void ADC_init(PinName_t pinName);
void JADC_init(PinName_t pinName);


// Multi-Channel Scan Sequence 
void ADC_sequence(PinName_t *seqCHn, int seqCHnums); 
void JADC_sequence(PinName_t *seqCHn, int seqCHnums); 


// ADC start
void ADC_start(void);

// flag for ADC interrupt
uint32_t is_ADC_EOC(void);
uint32_t is_ADC_OVR(void);
void clear_ADC_OVR(void);
uint32_t is_ADC_JEOC(void);
void clear_ADC_JEOC(void);

// read ADC value
uint32_t ADC_read(void);




/////////////////////////////////////////////////////
// Advanced Setting
/////////////////////////////////////////////////////
// Conversion mode change: CONT, SINGLE / Operate both ADC,JADC
void ADC_conversion(int convMode); 					
void ADC_trigger(TIM_TypeDef* TIMx, int msec, int edge);

// Private Function
void ADC_pinmap(PinName_t pinName, uint32_t *chN);
```

### (Option 2) Create your own library

Download the exercise files.

* [ecADC2\_student.c](https://github.com/ykkimhgu/EC-student/blob/main/include/lib-student)
* [ecADC2\_student.h](https://github.com/ykkimhgu/EC-student/blob/main/include/lib-student)

Change the file names as

* ecADC2.c
* ecADC2.h

**ecADC2.h**

**Fill-In missing code in ecADC2\_student.c**

You must update your header files in the directory `EC\include\`. and add in `ecSTM32F4v2.h`

{% tabs %}
{% tab title="ADC\_init()" %}

```c
void ADC_init(PinName_t pinName){
// ...
// ...
	// 2. Regular / Injection Group 
	//Regular: SQRx, Injection: JSQx

	// 3. Repetition: Single scan or Continuous scan conversion
	ADC1->CR2 |= ___________;      			// default : Continuous conversion mode	
	
	// 4. Single(one) Channel or Scan(multi-channel) mode  
	// Configure the sequence length		// default: one-channel length
	ADC1->SQR1 &= ___________; 				// 0000: one channel length in the regular channel conversion sequence
	
	// Configure the multiple channel sampling sequence 
	ADC1->SQR3 &= ~ADC_SQR3_SQ1;			// SQ1 clear 
	ADC1->SQR3 |= ___________; 				// Choose the first channelID to sample
	
	// Default:  Single(one-channel) Channel mode 
	ADC1->CR1 &= ___________;				// 0: One-channel mode 		
	
	// 5. Interrupt Enable
	// Enable EOC(conversion) interrupt. 
	ADC1->CR1 &= ~ADC_CR1_EOCIE;          	// Interrupt reset
	ADC1->CR1 |= ___________;           	// Interrupt enable
	
// ...
// ...
}
```

{% endtab %}

{% tab title="JADC\_init" %}

```c
void JADC_init(PinName_t pinName){
// ...
// ...
	// 2. Injection Group 
	//    Injection: JSQx

	// 3. Repetition: Single or Continuous conversion
	ADC1->CR2 |= _____________;     		// Enable Continuous conversion mode	
	
	// 4. Single Channel or Scan mode
	//  - Single Channel: scan mode, right alignment	
	ADC1->CR1 |= _____________;			// 1: Scan mode enable 
	ADC1->CR2 &= _____________;   			// 0: Right alignment	

	// Configure the injected channel sequence length
	ADC1->JSQR &= _____________; 			// 00: conversion in the inject channel

	// Configure the injected channel sequence 
	ADC1->JSQR &= ~ADC_JSQR_JSQ1;			// SQ1 clear bits
	ADC1->JSQR |= _____________; 			// Choose the channel to convert firstly

	// 5. Interrupt Enable
	// Enable JEOC(conversion) interrupt.
	ADC1->CR1 &= ~ADC_CR1_JEOCIE;   		// JEOC interrupt reset
	ADC1->CR1 |= _____________;			// JEOC interrupt enable
		
// ...
// ...
}
```

{% endtab %}
{% endtabs %}

### Example Code

Check your library files by running the following examples.

#### **Example 1: One Analog sensor (ADC)**

* Single-Channel, Continuous Scan
* 1msec ADC triggering with TIM3

```cpp
#include "ecSTM32F4v2.h"
// #include "ecADC.h"


//IR parameter//
uint32_t value;

void setup(void);
	
int main(void) { 
	
	// Initialiization --------------------------------------------------------
	setup();
	
	// Inifinite Loop ----------------------------------------------------------
	while(1){
		printf("value = %d \r\n",value);
		printf("\r\n");
		delay_ms(1000);
	}
}

// Initialiization 
void setup(void)
{	
	RCC_PLL_init();		// System Clock = 84MHz
	UART2_init();		// UART2 Init
	SysTick_init();		// SysTick Init
	ADC_init(PB_0);		// Default: HW triggered by TIM3 counter @ 1msec
}

// ADC Interrupt - End-of-Conversion
void ADC_IRQHandler(void){
	if(is_ADC_EOC()) {
		// if(is_ADC_OVR()) clear_ADC_OVR();	
		// User Code Goes Here
		value = ADC_read();
		// clear_ADC_EOC();  // Reading ADC clears EOC flag
	}		
}

```

#### **Example 2: Multiple Analog sensors (JADC)**

* Multi-Channel(2 channels), Continuous Scan
* 1msec ADC triggering with TIM3
* (ADC) Channel Sequence:
  * SQ1=ADC\_CH\_8(PB\_0) to SQ2=ADC\_CH\_9(PB\_1)
* (JADC): Channel Sequence:
  * JSQ1=ADC\_CH\_8(PB\_0)(PB\_0) to JSQ1=ADC\_CH\_9(PB\_1)

{% hint style="info" %}
**Use JADC instead of ADC for multiple-channel ADC**
{% endhint %}

{% tabs %}
{% tab title="JADC" %}
**JADC: Has its own data register for each ADC channels**

```cpp
#include "ecSTM32F4v2.h"
// #include "ecADC.h"

//IR parameter//
uint32_t value1, value2;
PinName_t seqCHn[2] = {PB_0, PB_1};

void setup(void);

int main(void) { 
	// Initialiization --------------------------------------------------------
	setup();
	
	// Inifinite Loop ----------------------------------------------------------
	while(1){
		printf("value1 = %d \r\n",value1);
		printf("value2 = %d \r\n",value2);
		printf("\r\n");
		
		delay_ms(1000);
	}
}

// Initialiization 
void setup(void)
{	
	RCC_PLL_init();                 // System Clock = 84MHz
	UART2_init();			// UART2 Init
	SysTick_init();			// SysTick Init
	
	// ADC Init  Default: HW triggered by TIM3 counter @ 1msec
	JADC_init(PB_0);
	JADC_init(PB_1);

	// ADC channel sequence setting
	JADC_sequence(seqCHn, 2);
}


void ADC_IRQHandler(void){
	// if(is_ADC_OVR()) clear_ADC_OVR();	
	if(is_ADC_JEOC()){		// after finishing sequence ADC
		value1 = JADC_read(1);
		value2 = JADC_read(2);
		clear_ADC_JEOC();
	}
}

```

{% endtab %}

{% tab title="ADC" %}
**ADC: Shares the same data register from multiple channels**

```c
#include "ecSTM32F4v2.h"
// #include "ecADC.h"

//IR parameter//
uint32_t value1, value2;
int flag = 0;
PinName_t seqCHn[2] = {PB_0, PB_1};

void setup(void);

int main(void) { 
	// Initialiization --------------------------------------------------------
	setup();
	
	// Inifinite Loop ----------------------------------------------------------
	while(1){
		printf("value1 = %d \r\n",value1);
		printf("value2 = %d \r\n",value2);
		printf("\r\n");
		
		delay_ms(1000);
	}
}

// Initialiization 
void setup(void)
{	
	RCC_PLL_init();                         // System Clock = 84MHz
	UART2_init();				// UART2 Init
	SysTick_init();				// SysTick Init
	
	// ADC Init  Default: HW triggered by TIM3 counter @ 1msec
	ADC_init(PB_0);
	ADC_init(PB_1);

	// ADC channel sequence setting
	ADC_sequence(seqCHn, 2);
}


void ADC_IRQHandler(void){
	if(is_ADC_OVR())
		clear_ADC_OVR();
	
	if(is_ADC_EOC()){		// after finishing sequence
		if (flag==0)
			value1 = ADC_read();  
		else if (flag==1)
			value2 = ADC_read();
			
		flag =! flag;		// flag toggle
	}
}
```

{% endtab %}
{% endtabs %}

## Problem 2: Measurement from multiple analog sensors

### IR Reflective Sensors (TCRT 5000)

First, download and read IR Reflective Sensor(TCRT 5000): [Spec Sheet](https://www.devicemart.co.kr/goods/download?id=1327416\&rank=1)

TCRT5000 and TCRT5000L are reflective sensors that include an infrared emitter and phototransistor in a leaded package, which blocks visible light.

![image](https://user-images.githubusercontent.com/91526930/200573269-26a4ffa1-c789-4545-9dc5-079294265d4d.png)

**The HC-SR04 Ultrasonic Range Sensor Features:**

* Input Voltage : 5V
* Detector type: phototransistor
* Operating range within > 20 % relative collector current: 0.2 mm to 15 mm
* Emitter wavelength: 950 nm

**APPLICATIONS**

* Position sensor for shaft encoder
* Detection of reflective material such as paper, IBM cards, magnetic tapes etc.
* Limit switch for mechanical motions in VCR

### Procedure

1. Create a new project under the directory `\repos\EC\LAB\LAB_ADC`

* The project name is “**LAB\_ADC\_IR”**
* Create a new source file named as “**LAB\_ADC\_IR.c”**

> You MUST write your name on the source file inside the comment section.

2\. Update and use **ecSTM32F411.h**. This header should be defined as explained in

### Configuration

| Type             | Port - Pin                                                              | Configuration                                                                                                                                                                                                                 |
| ---------------- | ----------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **System Clock** |                                                                         | PLL 84MHz                                                                                                                                                                                                                     |
| **GPIO**         | <p>PB\_0<br>PB\_1</p>                                                   | <p>Analog Mode<br>No Pull-up Pull-down</p>                                                                                                                                                                                    |
| **ADC (JADC)**   | <p>PB\_0: ADC1\_CH8 (1st channel)<br>PB\_1: ADC1\_CH9 (2nd channel)</p> | <p>ADC Clock Prescaler /8<br>12-bit resolution, right alignment<br>Continuous Conversion mode<br>Scan mode: Two channels in regular group<br>External Trigger (Timer3 Trigger) @ 1kHz<br>Trigger Detection on Rising Edge</p> |
| **TIM3**         |                                                                         | <p>Up-Counter, Counter CLK 1kHz<br>OC1M(Output Compare 1 Mode) : PWM mode 1<br>Master Mode Selection: (Trigger) OC1REF</p>                                                                                                    |

### Line Tracing

![line](https://github.com/ykkimhgu/EC-student/assets/84508106/8092b591-4e70-49b3-8690-4e9e09642bd1)

* Create a logic to trace a dark line on white background surface for your RC car.
* Use 2 IR reflective sensors to detect if the black line is in between the sensors. It should display whether the system needs to move **Left or Right** to keep the line between sensors.
* Set the ADC sampling rate trigger to be 1KHz
* Determine the threshold value to differentiate dark and white surface of the object.
* Display (1) and (2) on serial monitor of Tera-Term. Print the values every second.

  ​ (1) reflection value of IR1 and IR2

  ​ (2) print ‘GO LEFT’ or ‘GO ‘RIGHT’

**Display Example**

![image](https://user-images.githubusercontent.com/91526930/200577686-909a4cb7-1af9-459a-8afa-aaaee64aa448.png)

### Circuit Diagram

> You need to include the circuit diagram

![image](https://user-images.githubusercontent.com/38373000/192134563-72f68b29-4127-42ac-b064-2eda95a9a52a.png)

### Discussion

1. How would you change the code if you need to use 3 Analog sensors?

> Answer discussion questions

2. Which registers should be modified if you need to use Injection Groups instead of regular groups for 2 analog sensors?

   > Answer discussion questions

### Code

Your code goes here: [ADD Code LINK such as github](https://github.com/ykkimhgu/EC-student/)

Explain your source code with necessary comments.

```
// YOUR MAIN CODE ONLY
// YOUR CODE
```

### Results

Experiment images and results

> Show experiment images /results

Add [demo video link](https://github.com/ykkimhgu/course-doc/blob/master/ec-course/lab/link/README.md)

## Reference

Complete list of all references used (github, blog, paper, etc)

```
```

## Troubleshooting

(Option) You can write Troubleshooting section


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ykkim.gitbook.io/ec/ec-course/lab/lab-adc-irsensor.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
